How to search node value using loop in XSLT?

扶醉桌前 提交于 2019-12-25 02:27:12

问题


From below code I want to check whether network B is present in one of the operator station node or not. If present then returns true or false. Actually I want to achieve the code like break statement in loop. But as break is not exist in XSLT then please suggest me solution to achieve it. Please follow the same code and suggest using key or variable value as list of record.

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>

And 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>

Expected Output:

True


回答1:


As Ian Roberts has already suggested in his answer to your earlier question, you will do better in XSLT if you learn to think declaratively rather than procedurally. (Learning to do so may also make you a better programmer in procedural languages, too, and not just in XSLT, but that's a risk you have to take.)

So the first thing to do is to stop thinking that your goal is "to achieve the code like break statement in loop". That's a silly goal -- if you really want to program with break statements in loops, choose a language that has loops and break statements and go wild. If you want to solve your problem in XSLT, you need to understand your goals declaratively. In a procedural language, you would use a loop here -- to do what? What problem does a loop statement with a break solve in a procedural language? Solve that problem in XSLT, and you're done.

Your description of your goal (incomplete and implausible as it is) says you want to return true if some OperatorStation element has a child node named Network B, and false otherwise. You propose to iterate over the OperatorStation elements looking for one with a child named Network B, and return true if you hit one, false if you reach the end without hitting one.

Why not just return true if such an OperatorStation element exists, false otherwise?

<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>

If what you really want to do is do one thing if and only if there is an OperatorStation with a child named 'Network B' and something else otherwise, then replace 'true' and 'false' above with the appropriate instructions.

If what you really want to do is set a variable to signal whether there is an OperatorStation with a child named 'Network B', so you can use it in some conditional processing at various points, then setting a variable with an appropriate XPath expression is simple:

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

No loop is needed here: XPath takes care of the implicit iteration.

Think with your tools, not against them. It makes programming a lot more fun.




回答2:


You're correct that there is no xsl:break to go along with xsl:for-each.

The usual approach instead is to be more selective in controlling one of the following:

  • whether to start the loop
  • what to iterate over
  • what to apply templates to

Without seeing your desired output, I cannot be more specific, but the general concepts are useful regardless of the details:

Control whether to start the loop (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>

Control what to iterate over (Better)

<!-- 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>

Control what to apply templates to (Best)

<!-- 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 -->

Note that I do not mean to imply that these outcomes are all the same. (You do not specify what your desired output is, so I took liberties.)

Working with XSLT in a declarative manner is different than using the usual procedural approach common to other languages but really does work well in the end if given the chance.




回答3:


As you already know that there is no option to break-out of for-each loop. But there is an option to check if "Name" elements with value 'Network B' exists or not. Though not efficient, this solution works for me

<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>


来源:https://stackoverflow.com/questions/24247204/how-to-search-node-value-using-loop-in-xslt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!