使用xsl计算xml节点中的单词数

时间:2011-05-31 13:16:58

标签: xml xslt

以下是示例xml文档。

<root>
  <node> count the number of words </node>
</root>

对于这个例子,我想计算xslt中节点“”中的单词数。

输出就像是单词数量:: 5

对此有何想法?

您的(Dimitre Novatchev)代码适用于上述xml。 您的代码是否适用于以下xml?

<root>

<test>
   <node> pass pass </node>
</test>

  <test>
      <node> fail pass fail </node>
  </test>

  <test>
      <node> pass pass fail </node>
  </test>

 </root>

输出如:节点“node”中的单词总数:8

UPDATE3 ::

此代码完全适用于上述xml doc。 假设

<root>
<test>
   <node> pass pass </node>
   <a> value </a>
   <b> value </b>
</test>

  <test>
      <node> fail fail </node>
      <b> value </b>
  </test>

  <test>
      <node> pass pass</node>
      <a> value </a>
  </test>
 </root>

但是您的代码会计算整个文档中的单词数。 我想只计算节点类型“node”中的单词数。 输出如

“node”中的单词数:6 总传球:: 4 总失败:: 2

感谢名单 Sathish所在

3 个答案:

答案 0 :(得分:11)

使用此XPath单行

  string-length(normalize-space(node)) 
- 
  string-length(translate(normalize-space(node),' ','')) +1

以下是使用XSLT的简短验证

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

 <xsl:template match="/*">
  <xsl:value-of select=
   " string-length(normalize-space(node))
    -
     string-length(translate(normalize-space(node),' ','')) +1"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<root>
    <node> count the number of words </node>
</root>

产生了想要的正确结果:

5

解释:使用标准XPath函数normalize-space()translate()string-length()

<强> UPDATE1

OP问道:

  

“你的(Dimitre Novatchev)代码是   上面的xml工作正常。是   您的代码将适用于以下内容   XML?“

<root>
  <test>
      <node> pass pass </node>
  </test>
  <test>
      <node> fail pass fail </node>
  </test>
  <test>
      <node> pass pass fail </node>
  </test>
</root>

回答:可以使用相同的方法:

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

    <xsl:template match="/">
        <xsl:value-of select=
        "string-length(normalize-space(.))
        -
         string-length(translate(normalize-space(.),' ','')) +1
         "/>
    </xsl:template>
</xsl:stylesheet>

在新提供的XML文档(上面)上使用此转换时,会生成所需的正确答案

8

Update2 :OP随后在评论中提问:

  

“我可以与...进行比较吗?   具有默认值的节点中的单词   字。 Conside节点包含值   "pass pass fail"。我想算一算   通过次数和失败次数。   喜欢pass=2 fail=1。可能吗?   帮帮我“

<强>答案

同样的方法也适用于这个问题的修改(在一般情况下,你需要一个很好的标记化 - 请在新问题中询问我这个问题):

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

    <xsl:template match="node">
        pass: <xsl:value-of select=
                "string-length()
                -
                 string-length(translate(.,'p',''))
         "/>
<xsl:text/>     fail: <xsl:value-of select=
                "string-length()
                -
                 string-length(translate(.,'f',''))
         "/>
    </xsl:template>
</xsl:stylesheet>

当对最后一个XML文档(上面)应用此转换时,会生成所需的正确

    pass: 2     fail: 0
    pass: 1     fail: 2
    pass: 2     fail: 1

答案 1 :(得分:1)

在xslt中我认为您需要处理以删除任何双倍间距,然后计算剩余空格以找到答案。虽然我确定有更好的方法!

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="root">
        <xsl:for-each select="node">
                <xsl:call-template name="word-count">
                        <xsl:with-param name="data" select="normalize-space(.)"/>
                        <xsl:with-param name="num" select="1"/>
                </xsl:call-template>
        </xsl:for-each>
</xsl:template>

    <xsl:template name="word-count">
            <xsl:param name="data"/>
            <xsl:param name="num"/>
            <xsl:variable name="newdata" select="$data"/>
            <xsl:variable name="remaining" select="substring-after($newdata,' ')"/>                

            <xsl:choose>
                    <xsl:when test="$remaining">
                            <xsl:call-template name="word-count">
                                    <xsl:with-param name="data" select="$remaining"/>
                                    <xsl:with-param name="num" select="$num+1"/>
                            </xsl:call-template>
                    </xsl:when>
                    <xsl:when test="$num = 1">
                            no words...
                    </xsl:when>
                    <xsl:otherwise>
                            <xsl:value-of select="$num"/>
                    </xsl:otherwise>
            </xsl:choose>                
    </xsl:template>

</xsl:stylesheet>

这个示例代码有效,从我用过的样式表中修改了它,它将一些遗留代码处理成有用的html输出!

更新代码以改进错误,捕获重复的空格并捕获空节点:&gt;

更新以解决其他问题!

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

        <xsl:template match="root">
        <xsl:for-each select="test/node">
                <xsl:call-template name="word-count">
                        <xsl:with-param name="data" select="normalize-space(.)"/>
                        <xsl:with-param name="num" select="1"/>
                        <xsl:with-param name="pass" select="0"/>
                        <xsl:with-param name="fail" select="0"/>
                </xsl:call-template>
        </xsl:for-each>
</xsl:template>

<xsl:template name="word-count">
        <xsl:param name="data"/>
        <xsl:param name="num"/>
        <xsl:param name="fail"/>
        <xsl:param name="pass"/>
        <xsl:variable name="newdata" select="$data"/>
        <xsl:variable name="first">
                <xsl:choose>
                        <xsl:when test="substring-before($newdata,' ')">
                                <xsl:value-of select="substring-before($newdata,' ')"/>  
                        </xsl:when>
                        <xsl:otherwise>
                                <xsl:value-of select="$newdata"/>
                        </xsl:otherwise>
                </xsl:choose>
        </xsl:variable> 
        <xsl:variable name="remaining" select="substring-after($newdata,' ')"/>
        <xsl:variable name="newpass">
                <xsl:choose>
                        <xsl:when test="$first='pass'">
                                <xsl:value-of select="$pass+1"/>
                        </xsl:when>
                        <xsl:otherwise>
                                <xsl:value-of select="$pass"/>
                        </xsl:otherwise>
                </xsl:choose>
        </xsl:variable>        
        <xsl:variable name="newfail">
                <xsl:choose>
                        <xsl:when test="$first='fail'">
                                <xsl:value-of select="$fail+1"/>
                        </xsl:when>
                        <xsl:otherwise>
                                <xsl:value-of select="$fail"/>
                        </xsl:otherwise>
                </xsl:choose>
        </xsl:variable>

        <xsl:choose>
                <xsl:when test="$remaining">
                        <xsl:call-template name="word-count">                        
                                <xsl:with-param name="data" select="$remaining"/>
                                <xsl:with-param name="num" select="$num+1"/>
                                <xsl:with-param name="pass" select="$newpass"/>
                                <xsl:with-param name="fail" select="$newfail"/>
                        </xsl:call-template>
                </xsl:when>
                <xsl:when test="$num = 1">
                        it was empty
                </xsl:when>
                <xsl:otherwise>
                        <xsl:value-of select="$first"/>
                        wordcount:<xsl:value-of select="$num"/>
                        pass:<xsl:value-of select="$newpass"/>
                        fail:<xsl:value-of select="$newfail"/><br/>
                </xsl:otherwise>
        </xsl:choose>
</xsl:template>
</xsl:stylesheet>

答案 2 :(得分:0)

这是我刚刚根据上面的Dimitre Novatchev的答案建立的XSLT。 它根据root / data / value计算单词(这适用于.NET资源文件[.RESX]),但您可以轻松地对其进行调整。

关于它使用的节点集函数,请参阅XSLT中提到的关于如何使用支持EXSLT的处理器或其他本机支持此函数的URL(使用msxml命名空间用于.NET / MSXML,可以很容易改变,以引用EXSLT等。)

<?xml version="1.0" encoding="UTF-8"?>

<!--
Filename: ResX_WordCount.xsl
Version: 20141006
-->

<xsl:stylesheet 
  version="1.0"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  >

  <xsl:output method="text" indent="yes"/>

  <xsl:template match="/root">
    <!-- see http://www.xml.com/pub/a/2003/07/16/nodeset.html -->
    <xsl:variable name="WordCounts">
      <xsl:for-each select="data/value">
        <!-- see http://stackoverflow.com/questions/6188189/count-the-number-of-words-in-a-xml-node-using-xsl/ -->
        <count>
          <xsl:value-of select="string-length(normalize-space(text())) - string-length(translate(normalize-space(text()),' ','')) + 1"/>
        </count>
      </xsl:for-each>
    </xsl:variable>

    <xsl:value-of select="sum(msxsl:node-set($WordCounts)/count)"/>
  </xsl:template>

</xsl:stylesheet>