XQuery 构造具有顺序祖先节点名称的字符串对象

XQuery constructs string object with sequential ancestor node names

a.xml:

<execution xmlns="http://www.example.org">
  <header>
    <messageId>FX123</messageId>
  </header>
  <isCorrection>false</isCorrection>
  <trade>
    <tradeHeader>
      <partyTradeIdentifier>
        <partyReference href="ptyA"/>
        <tradeId>12345</tradeId>
      </partyTradeIdentifier>
      <tradeDate>2019-12-21</tradeDate>
    </tradeHeader>
    <fxTargetKnockoutForward>
      <target>
        <accumulationRegion>
          <lowerBound>
            <condition>AtOrAbove</condition>
          </lowerBound>
          <upperBound>
            <condition>Below</condition>
          </upperBound>
        </accumulationRegion>
        <accumulationRegion>
          <lowerBound>
            <condition>AtOrAbove</condition>
            <initialValue>1.1000</initialValue>
          </lowerBound>
          <multiplier>2</multiplier>
        </accumulationRegion>
        <knockoutLevel>
          <amount>
            <currency>CAD</currency>
            <amount>100000.00</amount>
          </amount>
          <targetStyle>Exact</targetStyle>
        </knockoutLevel>
      </target>
      <expirySchedule>
        <adjustedDate>2019-12-23</adjustedDate>
        <adjustedDate>2020-01-27</adjustedDate>
        <adjustedDate>2020-02-25</adjustedDate>
        <adjustedDate>2020-03-26</adjustedDate>
      </expirySchedule>
      <settlementSchedule>
        <dateAdjustments>
          <businessDayConvention>FOLLOWING</businessDayConvention>
          <businessCenters>
            <businessCenter>CATO</businessCenter>
            <businessCenter>USNY</businessCenter>
          </businessCenters>
        </dateAdjustments>
        <adjustedDate>2019-12-24</adjustedDate>
        <adjustedDate>2020-01-28</adjustedDate>
        <adjustedDate>2020-02-26</adjustedDate>
        <adjustedDate>2020-03-27</adjustedDate>
      </settlementSchedule>
      <fixingInformationSource>
        <rateSource>Reuters</rateSource>
        <rateSourcePage>WMRSPOT09</rateSourcePage>
      </fixingInformationSource>
    </fxTargetKnockoutForward>
  </trade>
</execution>

Logic: I pass in-memory XML (a.xml) and targeted element (“trade”) as parameters -> the function local:array-qname evaluates all of this element’s descendants -> Whenever the descendant’s node name is the same as its sibling’s node name, it is considered a candidate -> the function walks backwards to retrieve all of its ancestor node name (except the root node) up to the passed element (“trade”) level.

The desired result: string array objects, of each object contains all of the candidate's sequential ancestor node names and its own node name. The expected result is:

( ("trade","fxTargetKnockoutForward","target","accumulationRegion"),
("trade","fxTargetKnockoutForward","expirySchedule","adjustedDate"),
("trade","fxTargetKnockoutForward","settlementSchedule","dateAdjustments","businessCenters","businessCenter"),
("trade","fxTargetKnockoutForward","settlementSchedule","adjustedDate") )

库模块是:

xquery version "1.0-ml";
declare function local:array-qname(
  $doc as node()*,
  $element as xs:string
) as xs:string*
{
  let $e := $doc//*[name() = $element]
  for $d in $e/descendant::*[name() = name(following-sibling::*[1])],
      $a in $d/ancestor::*[not(name() = name($doc/*))]/name(.)
  return 
    for $_ in $a
    return
      <a>
       ( {xs:QName($a)},{xs:QName(local-name($d))} )
      </a>  
};
let $doc := doc("a.xml")
return
  local:array-qname($doc, "trade")

但是出了问题:

(trade,fxTargetKnockoutForward,target,accumulationRegion),
(trade,fxTargetKnockoutForward,expirySchedule,adjustedDate),
(trade,fxTargetKnockoutForward,settlementSchedule,dateAdjustments,businessCenters,businessCenter),
(trade,fxTargetKnockoutForward,settlementSchedule,adjustedDate),      

如何让我的模块工作?

declare variable $element-name as xs:QName external := QName('http://www.example.org', 'trade');

let $base := //*[node-name() = $element-name]
for $d in $base//*[node-name() = following-sibling::*[1]/node-name()]
return 
    '(' 
    || $element-name 
    || ': (' 
    || ($d/ancestor-or-self::* except $d/ancestor::*[node-name() = $element-name]/ancestor-or-self::*)/node-name() => string-join(', ')
    || '))'

我明白了

(trade: (fxTargetKnockoutForward, target, accumulationRegion))
(trade: (fxTargetKnockoutForward, expirySchedule, adjustedDate))
(trade: (fxTargetKnockoutForward, expirySchedule, adjustedDate))
(trade: (fxTargetKnockoutForward, expirySchedule, adjustedDate))
(trade: (fxTargetKnockoutForward, settlementSchedule, dateAdjustments, businessCenters, businessCenter))
(trade: (fxTargetKnockoutForward, settlementSchedule, adjustedDate))
(trade: (fxTargetKnockoutForward, settlementSchedule, adjustedDate))
(trade: (fxTargetKnockoutForward, settlementSchedule, adjustedDate))

我不确定你的描述“只要后代的节点名称与其兄弟的节点名称相同,它就被认为是候选者 -> 函数向后遍历以检索其所有祖先节点名称(根节点除外)节点)到传递的元素(“交易”)级别。”为什么重复 adjustedDate 不在您想要的输出中,因为样本似乎包含满足条件的该名称的各种元素。

以下解决方案符合要求……

declare function local:array-qname(
  $doc   as document-node(),
  $name  as xs:string
) {
  for $e in $doc//*[name() = $name]
  for $d in $e/descendant::*[name() = name(following-sibling::*[1])]
  return <a>{
   for $name in $d/ancestor-or-self::*[not(. << $e)]
   return node-name($name)
  }</a>
};

let $doc := doc('a.xml')
return local:array-qname($doc, 'trade')

…但它与预期的输出不同,因为它会产生重复的路径。如果要避免重复,并且字符串表示就足够了,可以使用distinct-values

  distinct-values(
    for $e in $doc//*[name() = $name]
    for $d in $e/descendant::*[name() = name(following-sibling::*[1])]
    return string-join($d/ancestor-or-self::*[not(. << $e)]/name(), ' ')
  )