XSLT 1.0选择'flag'节点之间的所有节点

时间:2016-07-01 19:41:30

标签: xml xslt xslt-1.0

以下面的XML为例:

<?xml version="1.0" encoding="UTF-8"?>
<HelloXml>
  <Greeting>Hello</Greeting>
  <Name>World</Name>
  <FriendList>
    <Friend>
      <Number>1</Number>
      <BestFriend id='start' />
    </Friend>
    <Friend>
      <Number>2</Number>
      <Name>Mercury</Name>
    </Friend>
    <Friend>
      <Number>3</Number>
      <BestFriend id='end' />
    </Friend>
    <Friend>
      <Number>4</Number>
      <Name>Venus</Name>
    </Friend>
    <!-- ... -->
    <Friend>
      <Number>7</Number>
      <BestFriend id='start' />
    </Friend>
    <Friend>
      <Number>8</Number>
      <Name>Saturn</Name>
    </Friend>
    <!-- ... -->
    <Friend>
      <Number>11</Number>
      <BestFriend id='end' />
    </Friend>
    <!-- ... -->
    <Friend>
      <Number>12</Number>
      <Name>Neptune</Name>
    </Friend>
  </FriendList>
</HelloXml>

我需要做几件事:

  • 获取“BestFriend”开头/结尾之间的所有“好友” flags(注意它们是兄弟节点,而不是子节点)。
  • 制作一系列我在那里的“BestFriends”。

想法是输出类似于:

<BestFriends>
  <Friend number='1'>
    <Name>Mercury</Name>
  </Friend>
  <Friend number='2'>
    <Name>Saturn</Name>
  </Friend>
</BestFriends>

我尝试过使用下一个兄弟,先前兄弟和其他逻辑,但到目前为止,没有运气。

欢迎任何建议。

感谢。

编辑:对不起,我搞砸了“结束”的旗帜。此外,我们正在使用XSLT 1.0。

编辑:现在需求已经改变,而且比以前更令人困惑。情况是一样的,但现在输出应该是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<FriendList>
  <Friend BestFriend="true">
    <Name>Mercury</Name>
  </Friend>
  <Friend BestFriend="false">
    <Name>Venus</Name>
  </Friend>
  <Friend BestFriend="true">
    <Name>Saturn</Name>
  </Friend>
  <Friend BestFriend="false">
    <Name>Neptune</Name>
  </Friend>
</FriendList>

为了将要求用语言表达,我需要不加歧视地输出所有“朋友”,但我需要添加一个属性来区分“BestFriends”和普通的“BestFriends”。这些BestFriends都是“开始/结束”标志内的所有内容。

@ michael.hor257k提供的先前解决方案非常酷且乐于助人(再次感谢man!),但我的用户更改了要求:/

我已尝试对“兄弟递归”方法进行一些修改,也尝试了一些“循环”(但这不是java,当然,它不起作用),并使用一些变量(在XSLT中是常量) ,所以它也不起作用。)

欢迎任何帮助!

1 个答案:

答案 0 :(得分:0)

假设您正在使用XSLT 1.0,并进一步假设您的输入示例不正确,您可以使用以下样式表基于称为&#34;兄弟递归&#34;的技术:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/HelloXml">
    <BestFriends>
        <xsl:apply-templates select="FriendList/Friend[BestFriend/@id='start']/following-sibling::Friend[1]"/>
    </BestFriends>
</xsl:template>

<xsl:template match="Friend">
    <Friend number="{Number}">
        <xsl:copy-of select="Name"/>
    </Friend>
    <xsl:apply-templates select="following-sibling::Friend[1][not(BestFriend/@id='end')]" />
</xsl:template>

</xsl:stylesheet>

应用于以下测试输入:

<HelloXml>
   <Greeting>Hello</Greeting>
   <Name>World</Name>
   <FriendList>
       <Friend>
         <Number>0</Number>
         <Name>Sun</Name>
      </Friend>
     <Friend>
         <Number>1</Number>
         <BestFriend id="start"/>
      </Friend>
      <Friend>
         <Number>2</Number>
         <Name>Mercury</Name>
      </Friend>
      <Friend>
         <Number>3</Number>
         <BestFriend id="end"/>
      </Friend>
      <Friend>
         <Number>7</Number>
         <BestFriend id="start"/>
      </Friend>
      <Friend>
         <Number>8</Number>
         <Name>Saturn</Name>
      </Friend>
      <Friend>
         <Number>9</Number>
         <Name>Pluto</Name>
      </Friend>
      <Friend>
         <Number>10</Number>
         <BestFriend id="end"/>
      </Friend>
       <Friend>
         <Number>11</Number>
         <Name>Moon</Name>
      </Friend>
   </FriendList>
</HelloXml>

结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<BestFriends>
   <Friend number="2">
      <Name>Mercury</Name>
   </Friend>
   <Friend number="8">
      <Name>Saturn</Name>
   </Friend>
   <Friend number="9">
      <Name>Pluto</Name>
   </Friend>
</BestFriends>

请注意,这假设 start end 标志节点之间至少有一个Friend节点。

为响应变更的要求而添加:

  

我需要输出所有&#34;朋友&#34;没有歧视,但我需要   添加一个属性来区分&#34; BestFriends&#34;从正常   那些。这些BestFriends都是其中的所有内容   &#34;开始/结束&#34;标志。

有一种非常简单的方法可以实现这一目标,但效率不高:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/HelloXml">
    <FriendList>
        <xsl:for-each select="FriendList/Friend[Name]">
            <Friend BestFriend="{count(preceding-sibling::Friend[BestFriend[@id='start']]) != count(preceding-sibling::Friend[BestFriend[@id='end']])}">
                <xsl:copy-of select="Name"/>
            </Friend>
        </xsl:for-each>
    </FriendList>
</xsl:template>

</xsl:stylesheet>

如果输入较大,您可能需要先考虑预处理最好的朋友(或不是最好的朋友),然后使用列表确定输出中BestFriend属性的值。