【问题标题】:Identify position of context node within another nodeset识别上下文节点在另一个节点集中的位置
【发布时间】:2012-05-25 09:58:27
【问题描述】:

我有一个如下所示的 XML 文档:

<Root>
    <Cover>
        <Cover_Ref Val="1"/>
        <Cover_Code Val="Food in transit"/>
        <AdditionalCover>
            <AdditionalCover_Area Val="Sussex"/>
        </AdditionalCover>
    </Cover>
    <Cover>
        <Cover_Ref Val="2"/>
        <Cover_Code Val="Frozen goods"/>
    </Cover>
    <Cover>
        <Cover_Ref Val="3"/>
        <Cover_Code Val="Business equipment"/>
        <AdditionalCover>
            <AdditionalCover_Area Val="Sussex"/>
        </AdditionalCover>
    </Cover>
    <AdditionalCoverResult>
        <CoverArea Val="Sussex"/>
        <CoverExcluded Val="N"/>
    </AdditionalCoverResult>
    <AdditionalCoverResult>
        <CoverArea Val="Sussex"/>
        <CoverExcluded Val="Y"/>
    </AdditionalCoverResult>
</Root>

我需要把它变成这样的东西:

<Insurances>
    <Insurance>
        <reference>1</reference>
        <CoverType>Food in transit</CoverType>
        <Region>Sussex</Region>
        <Excluded>N</Excluded>
    </Insurance>
    <Insurance>
        <reference>2</reference>
        <CoverType>Frozen goods</CoverType>
    </Insurance>
    <Insurance>
        <reference>3</reference>
        <CoverType>Business equipment</CoverType>
        <Region>Sussex</Region>
        <Excluded>Y</Excluded>
    </Insurance>
</Insurances>

AdditionalCoverResult 元素指的是包含 AdditionalCover 元素的 Cover 元素 - 因此第一个 Cover 元素的封面不被排除,而第三个 Cover 元素的封面被排除。第二个封面元素没有 AdditionalCover,因此没有引用它的 AdditionalCoverResult 元素。

我的问题是,在&lt;xsl:for-each select="//Cover"&gt; 循环中,我想不出一种方法来确定我应该寻找哪个 AdditionalCoverResult 元素。在 for-each 中使用 position() 最终会导致我错误地为没有 AdditionalCover 的 Cover 元素输出 AdditionalCoverResult 信息。

我必须保留 Cover 的原始顺序,所以我不能做两个单独的循环,一个用于 Cover with AdditionalCover,一个用于 Cover without AdditionalCover。

//Cover 返回的节点集中,有没有办法可以识别上下文节点在//Cover[AdditionalCover] 返回的节点集中的位置?

我有点猜测,对于 Cover 元素,我需要考虑“我在 //Cover[AdditionalCover] 中的索引是什么,以便我可以使用该索引来识别我对应的 AdditionalCoverResult 元素?”

【问题讨论】:

    标签: xml xslt xpath


    【解决方案1】:

    这种转变

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:template match="/*">
      <Insurances>
       <xsl:apply-templates select="Cover"/>
      </Insurances>
     </xsl:template>
    
     <xsl:template match="Cover">
      <Insurance>
       <xsl:apply-templates/>
      </Insurance>
     </xsl:template>
    
     <xsl:template match="Cover_Ref">
      <reference><xsl:value-of select="@Val"/></reference>
     </xsl:template>
    
     <xsl:template match="Cover_Code">
      <CoverType><xsl:value-of select="@Val"/></CoverType>
     </xsl:template>
    
     <xsl:template match="AdditionalCover_Area">
      <Region><xsl:value-of select="@Val"/></Region>
    
      <Excluded>
        <xsl:value-of select=
        "/*/AdditionalCoverResult[CoverArea/@Val=current()/@Val]
                 [position()
                 =
                  1 +count(current()
                           /ancestor::Cover[1]
                              /preceding-sibling::Cover
                                [AdditionalCover
                                  /AdditionalCover_Area/@Val
                                =
                                 current()/@Val
                                ]
                          )
                  ]
                   /CoverExcluded/@Val
        "/>
      </Excluded>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时:

    <Root>
        <Cover>
            <Cover_Ref Val="1"/>
            <Cover_Code Val="Food in transit"/>
            <AdditionalCover>
                <AdditionalCover_Area Val="Sussex"/>
            </AdditionalCover>
        </Cover>
        <Cover>
            <Cover_Ref Val="2"/>
            <Cover_Code Val="Frozen goods"/>
        </Cover>
        <Cover>
            <Cover_Ref Val="3"/>
            <Cover_Code Val="Business equipment"/>
            <AdditionalCover>
                <AdditionalCover_Area Val="Sussex"/>
            </AdditionalCover>
        </Cover>
        <AdditionalCoverResult>
            <CoverArea Val="Sussex"/>
            <CoverExcluded Val="N"/>
        </AdditionalCoverResult>
        <AdditionalCoverResult>
            <CoverArea Val="Sussex"/>
            <CoverExcluded Val="Y"/>
        </AdditionalCoverResult>
    </Root>
    

    产生想要的正确结果

    <Insurances>
       <Insurance>
          <reference>1</reference>
          <CoverType>Food in transit</CoverType>
          <Region>Sussex</Region>
          <Excluded>N</Excluded>
       </Insurance>
       <Insurance>
          <reference>2</reference>
          <CoverType>Frozen goods</CoverType>
       </Insurance>
       <Insurance>
          <reference>3</reference>
          <CoverType>Business equipment</CoverType>
          <Region>Sussex</Region>
          <Excluded>Y</Excluded>
       </Insurance>
    </Insurances>
    

    【讨论】:

      【解决方案2】:

      您可以将您感兴趣的当前上下文部分存储在一个变量中 - 就像这样:

      <xsl:for-each select="//Cover">
      
        ...
      
        <xsl:variable name="additional" select="AdditionalCover/AdditionalCover_Area/@Val"/>
        <xsl:if select="$additional">
          <Excluded>
            <xsl:value-of select="AdditionalCoverResult[CoverArea/@Val = $additional]/CoverExcluded/@Val"/>
          </Excluded>
        </xsl:if>
      </xs:for-each>
      

      【讨论】:

      • 嗨尼克,我遇到的问题是带有 AdditionalCover 的两个 Cover 元素的 CoverArea 值是相同的 - 它们都是“Sussex”。这就是为什么我必须尝试在另一个节点集中找到我的上下文节点的索引。
      【解决方案3】:

      发布问题后,我在相关部分看到了一个链接 - xpath/xslt to determine index of context node relative to all nodes of same name?

      Dimitre Novatchev 的回答指出,通过使用

      count(preceding::question)+1
      

      您可以找到当前上下文节点相对于文档中所有question 元素的索引。

      对于我的问题,我使用了 count(preceding::Cover[AdditionalCover])+1 并且它有效 - 我希望我已经正确理解它,但它似乎确实可以解决问题。

      我不会立即选择此作为正确答案,因为如果有人有任何其他方法,我会非常感兴趣 - 我可能是 XSLT 的中级水平,这是了解更多关于它!

      【讨论】:

      • 您快到了——您当前的解决方案在一般情况下不起作用,即可能不止一个不同的区域具有不同的覆盖范围。您可能有兴趣查看完整且正确的解决方案。
      猜你喜欢
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      • 2016-02-09
      • 2016-08-23
      • 1970-01-01
      • 2014-09-01
      • 1970-01-01
      相关资源
      最近更新 更多