开发者

Check if string appears within node value in XSLT

I have the following XML:

<nodes>
  <node>
    <articles>125,1,9027</articles>
  </node>
  <node>
    <articles>999,48,123</articles>
  </node>
  <node>
    <articles>123,1234,4345,567</articles>
  </node>
</nodes>

I need to write some XSLT which will return only nodes which have a paricular article id, so in the example above, only those nodes which contain article 123.

My XSLT isn't great, so I'm struggling with this. I'd like to do something like this, but I know of course there isn't an 'instring' extension method in XSLT:

<xsl:variable name="currentNodeId" select="1234"/>

<xsl:for-each select="$allNodes [instring(articles,$currentNodeId)]">
  <!-- Output stuff -->
</xsl开发者_运维技巧:for-each>

I know this is hacky but not sure of the best approach to tackle this. The node-set is likely to be huge, and the number of article ids inside the nodes is likely to be huge too, so I'm pretty sure turning that splitting the value of the node and turning it into a node-set isn't going to be very efficient, but I could be wrong!

Any help as to the best way to do this would be much appreciated, thanks.


XSLT 2.0 : This will match articles which have exactly 123 somewhere as text.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="id" select="123"/>

<xsl:template match="/">
    <xsl:for-each select="//node[matches(articles, concat('(^|\D)', $id, '($|\D)'))]">
      <xsl:value-of select="current()"/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Sample input :

<?xml version="1.0" encoding="utf-8"?>
<nodes>
  <node>
    <articles>1234,1000,9027</articles>
  </node>
  <node>
    <articles>999,48,01234</articles>
  </node>
  <node>
    <articles>123,1234,4345,567</articles>
  </node>
  <node>
    <articles> 123 , 456 </articles>
  </node>
</nodes>

Output :

123,1234,4345,567

 123 , 456 

I don't know how to do this efficiently with XSLT 1.0 but as the OP said he is using XSLT 2.0 so this should be a sufficient answer.


In XSLT 1.0 you can use this simple solution, it uses normalize-space, translate, contains, substring, string-length functions.

Sample input XML:

<nodes>
  <node>
    <articles>125,1,9027</articles>
  </node>
  <node>
    <articles>999,48,123</articles>
  </node>
  <node>
    <articles>123,1234,4345,567</articles>
  </node>
  <node>
    <articles> 123 , 456 </articles>
  </node>
  <node>
    <articles>789, 456</articles>
  </node>
  <node>
    <articles> 123 </articles>
  </node>
  <node>
    <articles>456, 123 ,789</articles>
  </node>
</nodes>

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:variable name="id" select="123"/>

  <xsl:template match="node">
    <xsl:variable name="s" select="translate(normalize-space(articles/.), ' ', '')"/>

    <xsl:if test="$s = $id 
            or contains($s, concat($id, ','))
            or substring($s, string-length($s) - string-length($id) + 1, string-length($id)) = $id">
      <xsl:copy-of select="."/>
    </xsl:if>


  </xsl:template>

  <xsl:template match="/nodes">
    <xsl:copy>
      <xsl:apply-templates select="node"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Output:

<nodes>
  <node>
    <articles>999,48,123</articles>
  </node>
  <node>
    <articles>123,1234,4345,567</articles>
  </node>
  <node>
    <articles> 123 , 456 </articles>
  </node>
  <node>
    <articles> 123 </articles>
  </node>
  <node>
    <articles>456, 123 ,789</articles>
  </node>
</nodes>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜