使用 XSLT 计算 XML 中字符串出现的次数

发布于 2024-11-19 23:50:56 字数 791 浏览 2 评论 0原文

我想使用 XSLT 计算 XML 文档中特定节点中字符串出现的次数。 考虑这个例子

 <mainNode>
<book>
    <price> 100 </price>
    <city> chennai </city>
    <list>
        <language> c java ruby </language>
    </list>
</book>

<book>
    <price> 200 </price>
    <city> banglore </city>
    <list>
        <language> c java </language>
    </list>
</book>

<book>
    <price> 300 </price>
    <city> delhi </city>
    <list>
        <language> java ruby </language>
    </list>
</book>
</mainNode>      

在这里我想计算“java”的出现次数

我想要这样的输出:: java -- 3

如何做到这一点???有什么想法吗???

I want to calcutae the number of occurrences of a string in a particular node in XML document using XSLT.
Consider this example

 <mainNode>
<book>
    <price> 100 </price>
    <city> chennai </city>
    <list>
        <language> c java ruby </language>
    </list>
</book>

<book>
    <price> 200 </price>
    <city> banglore </city>
    <list>
        <language> c java </language>
    </list>
</book>

<book>
    <price> 300 </price>
    <city> delhi </city>
    <list>
        <language> java ruby </language>
    </list>
</book>
</mainNode>      

Here I want to count the occurrences of "java"

I Want Output like this:: java -- 3

How to do this??? any idea???

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏尔 2024-11-26 23:50:56

使用

count(/*/*/list/language[contains(., 'java')])

完整的 XSLT 转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
     java -- <xsl:value-of select=
       "count(/*/*/list/language[contains(., 'java')]) "/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java ruby </language>
        </list>
    </book>
</mainNode>

生成所需的正确结果

 java -- 3

更新

如果我们要计算字符串的所有出现次数 - 而不仅仅是包含该字符串的所有节点 - 以下是如何执行此操作:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:param name="pWord" select="' java '"/>

    <xsl:template match="/">
        <xsl:variable name="vResult">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:value-of select="concat($pWord, '--- ')"/>
        <xsl:value-of select="string-length($vResult)"/>
    </xsl:template>

    <xsl:template match="list/language" name="countWord">
        <xsl:param name="pText" select="."/>

        <xsl:if test="contains($pText, $pWord)">
            <xsl:text>X</xsl:text>
            <xsl:call-template name="countWord">
                <xsl:with-param name="pText"
                 select="concat(' ', substring-after($pText, $pWord))"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

当此转换应用于此 XML 文档

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java java ruby </language>
        </list>
    </book>
</mainNode>

想要的正确结果产生

 java --- 4

Use:

count(/*/*/list/language[contains(., 'java')])

The complete XSLT transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
     java -- <xsl:value-of select=
       "count(/*/*/list/language[contains(., 'java')]) "/>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java ruby </language>
        </list>
    </book>
</mainNode>

the wanted, correct result is produced:

 java -- 3

Update:

If we are to count all occurences of the string -- not just all nodes that contain the string -- here's how to do it:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:param name="pWord" select="' java '"/>

    <xsl:template match="/">
        <xsl:variable name="vResult">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:value-of select="concat($pWord, '--- ')"/>
        <xsl:value-of select="string-length($vResult)"/>
    </xsl:template>

    <xsl:template match="list/language" name="countWord">
        <xsl:param name="pText" select="."/>

        <xsl:if test="contains($pText, $pWord)">
            <xsl:text>X</xsl:text>
            <xsl:call-template name="countWord">
                <xsl:with-param name="pText"
                 select="concat(' ', substring-after($pText, $pWord))"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

when this transformation is applied on this XML document:

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java java ruby </language>
        </list>
    </book>
</mainNode>

the wanted, correct result is produced:

 java --- 4
世界和平 2024-11-26 23:50:56

也许你可以尝试这个XSL模板来计算子字符串

<xsl:template name="substring-count">
  <xsl:param name="string"/>
  <xsl:param name="substr"/>
  <xsl:choose>
    <xsl:when test="contains($string, $substr) and $string and $substr">
      <xsl:variable name="rest">
        <xsl:call-template name="substring-count">
          <xsl:with-param name="string" select="substring-after($string, $substr)"/>
          <xsl:with-param name="substr" select="$substr"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$rest + 1"/>
    </xsl:when>
    <xsl:otherwise>0</xsl:otherwise>
  </xsl:choose>
</xsl:template>

用法:

<xsl:call-template name="substring-count">
  <xsl:with-param name="string" select="'mary had a little lamb'" />
  <xsl:with-param name="substr" select="'lamb'" />
</xsl:call-template>

maybe you can try this XSL Template to count substrings:

<xsl:template name="substring-count">
  <xsl:param name="string"/>
  <xsl:param name="substr"/>
  <xsl:choose>
    <xsl:when test="contains($string, $substr) and $string and $substr">
      <xsl:variable name="rest">
        <xsl:call-template name="substring-count">
          <xsl:with-param name="string" select="substring-after($string, $substr)"/>
          <xsl:with-param name="substr" select="$substr"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$rest + 1"/>
    </xsl:when>
    <xsl:otherwise>0</xsl:otherwise>
  </xsl:choose>
</xsl:template>

Usage:

<xsl:call-template name="substring-count">
  <xsl:with-param name="string" select="'mary had a little lamb'" />
  <xsl:with-param name="substr" select="'lamb'" />
</xsl:call-template>
审判长 2024-11-26 23:50:56

语句中尝试:

count(//language[contains(concat(' ',.,' '), ' java ')])< /code>

如果您的文档结构相对静态,或者您在其他地方有名为 language 的节点用于其他目的,则可以将 //language 替换为/mainNode/book/list/language

concat 位可能看起来有点复杂,但通过确保您正在查找的文本的开头和结尾有空格,并搜索 ' java '两边都有空格,就不会错误地包含恰好包含 java 的其他术语,例如 javascript

如果“java”可能在一个节点中多次存在,那么您将需要使用递归模板。这是一种方法:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />
  <xsl:template match="/">
    <xsl:variable name="list">
      <xsl:for-each select="//language">
        <xsl:call-template name="count">
          <xsl:with-param name="lang">java</xsl:with-param>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:variable>
    <xsl:value-of select="concat('java -- ',string-length($list))" />
  </xsl:template>

  <xsl:template name="count">
    <xsl:param name="lang" />
    <xsl:param name="text" select="text()" />
    <xsl:if test="contains(concat(' ',$text,' '),concat(' ',$lang,' '))">
      <xsl:text>0</xsl:text>
      <xsl:call-template name="count">
        <xsl:with-param name="lang" select="$lang" />
        <xsl:with-param name="text" select="substring-after($text,$lang)" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

这实际上创建了一个由 0 组成的字符串,每个 java 出现一个,然后简单地使用该字符串的长度。

如果您可以选择使用 XSLT 2.0,则可以创建一个计算字符串中出现次数的函数,并使用 或类似的东西。

正如我在对您的问题的评论中指出的那样,更好地设计源 XML 会有很大帮助;如果一种语言的每次出现都有它自己的元素,那么这一切都是不必要的。当然,这可能超出您的控制范围,但如果您可以选择更改它(或说服提供商更改它),我强烈推荐它。

Try this in a <xsl:value-of> statement:

count(//language[contains(concat(' ',.,' '), ' java ')])

If your document structure is relatively static, or you have nodes called language elsewhere that serve another purpose, you can substitute //language for /mainNode/book/list/language.

The concat bit might seem a bit convoluted, but by making sure there's a space at the beginning and end of the text you're looking in, and searching for ' java ' with a space either side, you won't incorrectly include other terms that happen to include java, such as javascript.

If it's possible for 'java' to exist more than once in a node, then you'll need to use a recursive template. Here's one way:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />
  <xsl:template match="/">
    <xsl:variable name="list">
      <xsl:for-each select="//language">
        <xsl:call-template name="count">
          <xsl:with-param name="lang">java</xsl:with-param>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:variable>
    <xsl:value-of select="concat('java -- ',string-length($list))" />
  </xsl:template>

  <xsl:template name="count">
    <xsl:param name="lang" />
    <xsl:param name="text" select="text()" />
    <xsl:if test="contains(concat(' ',$text,' '),concat(' ',$lang,' '))">
      <xsl:text>0</xsl:text>
      <xsl:call-template name="count">
        <xsl:with-param name="lang" select="$lang" />
        <xsl:with-param name="text" select="substring-after($text,$lang)" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

This essentially creates a string of 0's, one for each occurrence of java, and then simply uses the length of that string.

If you have the option of using XSLT 2.0, you can create a function that counts the number of occurrences in a string, and use <xsl:value-of select="sum(mycountfunction(//language))" /> or something similar.

As I pointed out in a comment on your question, a better design of the source XML would have helped significantly; none of this is necessary if each occurrence of a language had it's own element. Of course that may be outside your control, but if you have the option of changing that (or persuading the provider to change it) I'd strongly recommend it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文