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



我正在两种不同的格式之间从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>

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

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

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

更有效的方法可能是按 B 前面最接近的非 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())

Ian 的回答真的很棒。我根本不反对这一点。但就我个人而言,我发现从递归函数的角度学习 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"/>

但是,如果这种解决方案没有帮助,请忽略它。

相关内容

  • 没有找到相关文章

最新更新