如何选择具有相同属性的后续行

时间:2014-02-27 15:32:11

标签: xml xslt xslt-1.0

我正在两种不同格式之间从xml转换为xml。

我的问题:
如何选择代码为“B”的子字段序列,该代码为“A”的后续兄弟,而不是任何其他字段的代码。 如果有人可以帮我弄清楚如何“选择”正确的节点

限制:
  - XSLT 1.0
  - 我无法更改数据字段中内容的顺序和由于    不同职位的数量。根据前后子字段应用不同的规则集   - 我不能使用特定的位置(不保证2个子场    'B'将遵循'A'或类似的)

例:
每个帖子都包含具有任意数量子字段的数据字段。

XML与此类似

<datafield tag="1">
      <subfield code="A"></subfield>
      <subfield code="B"></subfield>
      <subfield code="B"></subfield>
      <subfield code="C"></subfield>
      <subfield code="D"></subfield>
      <subfield code="B"></subfield>
      <subfield code="B"></subfield>
      <subfield code="G"></subfield>      
</datafield>

我的xslt:

<xsl:template match="datafield[@tag=1]">    
<xsl:choose>    
    <datafield>        
      <xsl:attribute name="tag">new tag</xsl:attribute>                    
      <!-- Do not transfer subfield code='X' -->
      <xsl:for-each select="./subfield[@code != 'X']">           
        <subfield>
          <xsl:choose>
            <xsl:when test="./@code = 'A'">
              <xsl:attribute name="code">New code</xsl:attribute>     
                <!-- Find siblings with the code 'B'.PROBLEM all fields with the code B is selected-->
              <xsl:when test="./following-sibling::subfield[@code='B']"> Apply operation here </xsl:when>
              </xsl:choose>
            </xsl:when>
          </xsl:choose>                
        </subfield>
        </xsl:if>
      </xsl:for-each>
    </datafield>
  </xsl:when>
</xsl:choose>

我是一个非常新的stackoverflow用户,所以如果我错过了任何重要的输入,请告诉我并添加它。

2 个答案:

答案 0 :(得分:0)

最直接的方法是根据计数做一些事情 - 选择所有以下的B,其前面的非Bs的数量与前面的非Bs加上一个 my 的数量相同(即我)

following-sibling::subfield[@code='B']
       [count(preceding-sibling::subfield[not(@code='B')])
      = count(current()/preceding-sibling::subfield[not(@code='B')]) + 1]

更有效的方法可能是定义一个将Bs按其最近的前一个非B分组

<xsl:key name="BbyNonB" match="subfield[@code='B']"
         use="generate-id(preceding-sibling::subfield[not(@code='B')][1])" />

然后您可以使用

立即提取当前(非B)子字段后面的所有B
key('BbyNonB', generate-id())

答案 1 :(得分:0)

伊恩的回答非常棒。我根本不反对。但就个人而言,我发现在递归函数方面学习XSLT更容易。如果您也是这种情况,请考虑此解决方案。同样,作为初学者,在函数调用方面进行思考对我来说更容易。但伊恩的回答显然更短更冷。

这是XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>                    
 <xsl:template match="subfield[@code='A']">
  <xsl:for-each select=".">
    <xsl:call-template name="getB">
      <xsl:with-param name="nodes" select="./following-sibling::subfield"/>
    </xsl:call-template>
  </xsl:for-each>
</xsl:template>

<xsl:template name="getB">
<xsl:param name="nodes"/>
  <xsl:choose>
     <xsl:when test="$nodes[1][@code='B']">
        <xsl:copy-of select="$nodes[1]"/>
        <xsl:call-template name="getB">
           <xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
        </xsl:call-template>
     </xsl:when>
     <xsl:otherwise/>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

对于此输入:

 <datafield tag="1">
  <subfield code="A"></subfield>
  <subfield code="B"></subfield>
  <subfield code="B"></subfield>
  <subfield code="C"></subfield>
  <subfield code="D"></subfield>
  <subfield code="B"></subfield>
  <subfield code="B"></subfield>
  <subfield code="G"></subfield>      
 </datafield>

你得到这个输出:

 <?xml version="1.0" encoding="utf-8"?>
  <subfield code="B"/>
  <subfield code="B"/>

但如果这种解决方案无济于事,那就完全忽略它。