如何在XSLT中使用循环搜索节点值?

时间:2014-06-16 15:29:07

标签: xslt xslt-1.0

从下面的代码我想检查网络B是否存在于其中一个操作员站节点中。如果存在则返回true或false。 其实我想在循环中实现像break语句这样的代码。但是由于XSLT中不存在中断,请建议我实现它的解决方案。 请遵循相同的代码,并建议使用键或变量值作为记录列表。

XSLT:

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:w3="http://www.w3.org">
  <xsl:output method="html" indent="yes"/>
  <xsl:variable name="allStations" 
                select="//w3:OperatorStation"/>
  <xsl:template match="/">
    <xsl:variable name="networks" select="$allStations"/>
    <xsl:for-each select="$networks">
      //check whether Network B is exist 
      // in any one OperatorStation node, 
      // if yes return true.
    </xsl:for-each>         
  </xsl:template>
</xsl:stylesheet>

和XML:

<?xml version="1.0" encoding="utf-8"?>
<OperatorStationCollection xmlns="http://www.w3.org" >
  <OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">        
    <Nodes>
      <ChildNodes>            
        <Name>Network A</Name>              
      </ChildNodes>          
    </Nodes>   
  </OperatorStation>      
  <OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Nodes>
      <ChildNodes>          
        <Name>Network B</Name>         
      </ChildNodes>        
    </Nodes>
  </OperatorStation>
  <OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Nodes>
      <ChildNodes>            
        <Name>Network A</Name>            
      </ChildNodes>              
    </Nodes>
  </OperatorStation>
</OperatorStationCollection>

预期产出:

3 个答案:

答案 0 :(得分:4)

正如Ian Roberts已经在his answer to your earlier question中建议的那样,如果你学会以声明方式而不是程序方式思考,那么你将在XSLT中做得更好。 (学习这样做也可能使你成为程序语言中更好的程序员,而不仅仅是在XSLT中,但这是你必须承担的风险。)

所以要做的第一件事就是不再认为你的目标是实现像循环中的break语句这样的代码&#34;。这是一个愚蠢的目标 - 如果你真的想在循环中使用break语句进行编程,那么选择一个具有循环和break语句的语言并且疯狂。如果您想在XSLT中解决问题,则需要以声明的方式理解您的目标。在过程语言中,你会在这里使用循环 - 做什么?带有break的循环语句在过程语言中解决了什么问题?在XSLT中解决这个问题,你就完成了。

您对目标的描述(不完整且难以置信)表示如果某个OperatorStation元素具有名为Network B的子节点,则返回true,否则返回false。您建议迭代使用名为Network B的子项的OperatorStation元素,如果您点击一个,则返回true,如果到达末尾而不点击一个,则返回false。

如果存在这样的OperatorStation元素,为什么不返回true,否则返回false?

<xsl:template match="/">
  <xsl:choose>
    <xsl:when test="//w3:OperatorStation
                    /w3:Nodes
                    /w3:ChildNodes
                    /w3:Name 
                    = 'Network B'">
      true
    </xsl:when>
    <xsl:otherwise>
      false
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

如果您真正想要做的是做一件事,当且仅当有一个名为&#39;网络B&#39;否则,别的东西,然后取代&#39; true&#39;并且&#39; false&#39;以上是适当的说明。

如果你真正想做的是设置一个变量来表示是否有一个名为&#39;网络B&#39;的孩子的OperatorStation,那么你可以在各个点的某些条件处理中使用它,然后设置具有适当XPath表达式的变量很简单:

<xsl:variable name="Opstation-with-child-B"
              select="//w3:OperatorStation
                     [w3:Nodes/w3:ChildNodes
                     /w3:Name = 'Network B']"/> 

这里不需要循环:XPath负责隐式迭代。

用你的工具思考,而不是反对它们。它使编程变得更有趣。

答案 1 :(得分:2)

你的xsl:break没有xsl:for-each,这是正确的。

通常的做法是更有选择性地控制下列之一:

  • 是否开始循环
  • 要迭代的内容
  • 将模板应用到
  • 的内容

如果没有看到你想要的输出,我就不能更具体了,但无论细节如何,一般概念都是有用的:

控制是否开始循环( Good

<!-- We want to loop only when no Network B's exist -->
<xsl:if test="//w3:OperatorStation[not(.//w3:ChildNodes/w3:Name = 'Network B')]"
   <xsl:for-each select="//w3:OperatorStation">
      <!-- ...  -->
   </xsl:for-each>
</xsl:if>

控制要迭代的内容(更好

<!-- We want to loop over all non-Network-B OperatorStations -->
<xsl:for-each select="//w3:OperatorStation[not(.//w3:ChildNodes/w3:Name = 'Network B')]">
      <!-- ...  -->
</xsl:for-each>

控制将模板应用到的内容(最佳

<!-- We want to apply templates to all non-Network-B OperatorStations -->
<xsl:apply-templates select="//w3:OperatorStation[not(.//w3:ChildNodes/w3:Name = 'Network B')]"/>

<!-- other templates handle each OperatorStation -->

请注意,我并不是要暗示这些结果都是一样的。 (你没有指定你想要的输出,所以我采取了自由。)

以声明方式使用XSLT与使用其他语言常用的通常程序方法不同,但如果有机会,最终确实可行。

答案 2 :(得分:1)

正如您已经知道的那样,没有选项可以突破for-each循环。但是可以选择是否存在值为“网络B”的“名称”元素。虽然效率不高,但这个解决方案对我有用

<xsl:template match="/">
    <xsl:variable name="is-Network-B">
        <xsl:for-each select="//w3:Name">
            <xsl:value-of select="if (matches(.,'Network B')) then '1' else ''"/>
        </xsl:for-each>
    </xsl:variable>

    <xsl:if test="$is-Network-B!=''">
        True
    </xsl:if></xsl:template>