【问题标题】:How to select following siblings until a certain sibling如何选择以下兄弟姐妹直到某个兄弟姐妹
【发布时间】:2018-07-03 15:07:50
【问题描述】:

我目前正在处理已使用自定义 xml 转换器转换为 xml 的 VDA 消息类型。但是,源文档中的每个标题和行记录都处于同一级别,如下例所示:

<root>
    <row>
        <Record_type>512</Record_type>
        <Customer_item_Number>A0528406</Customer_item_Number>
        <Supplier_item_number>10962915</Supplier_item_number>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>170306</Date>
        <Quantity>115</Quantity>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>190306</Date>
        <Quantity>97</Quantity>
    </row>
    <row>
        <Record_type>512</Record_type>
        <Customer_item_Number>A0528433</Customer_item_Number>
        <Supplier_item_number>10962916</Supplier_item_number>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>170306</Date>
        <Quantity>115</Quantity>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>170306</Date>
        <Quantity>115</Quantity>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>170306</Date>
        <Quantity>115</Quantity>
    </row>
    <row>
        <Record_type>513</Record_type>
        <Date>170306</Date>
        <Quantity>115</Quantity>
    </row>
</root>

(512) 记录类型是标题,下面的 (513) 记录类型是它上面的前面 (512) 记录的行。

我正在努力格式化此消息,以便行 (513) 在每个标题 (512) 记录下方缩进。

即所需的输出,类似这样。

<root>
    <Header>
        <Record_type>512</Record_type>
        <Customer_item_Number>A0528406</Customer_item_Number>
        <Supplier_item_number>10962915</Supplier_item_number>
        <Line>
            <Record_type>513</Record_type>
            <Date>170306</Date>
            <Quantity>115</Quantity>
        </Line>
        <Line>
            <Record_type>513</Record_type>
            <Date>190306</Date>
            <Quantity>97</Quantity>
        </Line>
    </Header>
    <Header>
        <Record_type>512</Record_type>
        <Customer_item_Number>A0528433</Customer_item_Number>
        <Supplier_item_number>10962916</Supplier_item_number>
        <Line>
            <Record_type>513</Record_type>
            <Date>170306</Date>
            <Quantity>115</Quantity>
        </Line>
        <Line>
            <Record_type>513</Record_type>
            <Date>170306</Date>
            <Quantity>115</Quantity>
        </Line>
        <Line>
            <Record_type>513</Record_type>
            <Date>170306</Date>
            <Quantity>115</Quantity>
        </Line>
        <Line>
            <Record_type>513</Record_type>
            <Date>170306</Date>
            <Quantity>115</Quantity>
        </Line>
    </Header>
</root>

我在使用以下同级方面取得了一些成功,但我无法将其与前同级联系起来,以便在下一个循环之前仅过滤掉所需的记录。

我希望有人能够提供帮助。 :)

【问题讨论】:

    标签: xpath xquery


    【解决方案1】:

    在 XQuery 3.1 中,您可以使用滚动窗口 https://www.w3.org/TR/xquery-31/#id-tumbling-windows

    <root>
    {    
    for tumbling window $record in root/row
    start $s when $s/Record_type = 512
    return
        <Header>
            {
                head($record)/*,
                tail($record) !
                    <Line>
                        { * }
                    </Line>
            }
        </Header>
    }
    </root>
    

    https://xqueryfiddle.liberty-development.net/gWcDMef

    【讨论】:

      【解决方案2】:

      如果您的 XQuery 处理器支持 XQuery 3.0window clauses,那么您的查询(至少在概念上)非常直接且高效:

      <root>{
        for tumbling window $w in /root/row
            start when true()
            end next $n when $n/Record_type = '512'
        return <Header>{
          head($w)/*,
          for $line in tail($w)
          return <Line>{$line/*}</Line>
        }</Header>
      }</root>
      

      否则,您必须使用 preceding-siblingfollowing-sibling XPath 轴,Mads Hansen 在他的回答中也显示:

      <root>{
        for $header in /root/row[Record_type = '512']
        return <Header>{
          $header/*,
          for $line in $header/following-sibling::row[Record_type = '513']
          let $prev-headers := $line/preceding-sibling::row[Record_type = '512']
          where $prev-headers[last()] is $header
          return <Line>{$line/*}</Line>
        }</Header>
      }</root>
      

      这里我们首先获取当前标题之后的所有行,然后检查每一行是否之前的最后一个标题是当前标题。这里重要的是使用is 而不是=eq,因为后两者仅适用于原子项目。这意味着在执行比较之前,XML 节点被原子化(即,被剥离成它们连接的文本内容)。 is 运算符比较 节点身份

      【讨论】:

      • 这正是我的要求。在我的映射工具中,我确实使用翻滚成功地检索了结果。但是,在我们的实际环境中,它不受支持。谢谢。
      【解决方案3】:

      对于每个具有Record_type512row,创建一个Header 元素。

      为了找到Line 元素的相关组的row 元素,您需要从512 个Record_type = 513 和第一个preceding-sibling 中选择following-siblingrow 元素当前标题。

      for $header in $doc/root/row[Record_type = 512]
      let $lines := $header/following-sibling::row[Record_type = 513]
                      [preceding-sibling::row[Record_type = 512][1] = $header] 
      return 
        <Header>{ 
          $header/*,
          for $line in $lines
          return <Line>{ $line/* }</Line>
        }</Header>
      

      【讨论】:

      • preceding-sibling::row[Record_type = 512] 的结果按文档顺序排列,因此您需要将$header 与最后一个进行比较,对吧?比较还应该是文档身份(使用is)而不是原子化的文本内容(由=强制)。
      • 我很接近,谢谢。我现在有了我想要的输出。
      猜你喜欢
      • 1970-01-01
      • 2012-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多