XSLT - 计算节点并将计数数作为属性

时间:2015-08-04 08:08:36

标签: xml xslt xslt-2.0

我有一个xml文件,如下所示,

<session>
  <p>Cricket<s/><s/><s/><s/> was first played England<s/> in or before the<s/><s/> 16th century.</p>
  <p>By the end of<s/><s/><s/> the 18th century, it had developed <s/><s/>to be the national sport of England.</p>
  <p>The expansion<s/><s/> of the British Empire led to cricket<s/><s/><s/><s/><s/> being played overseas and by the mid-19th century</p> 
</session>

<s>个节点内有<p>个节点。我的目标是计算连续的<s>个节点,并将计数作为<s>个节点中的属性。 所以输出应如下所示,

<session>
  <p>Cricket<s count="4"/> was first played in southern England<s count="1"/> in or before the<s count="2"/> 16th century.</p>
  <p>By the end of<s count="3"/> the 18th century, it had developed <s count="2"/>to be the national sport of England.</p>
  <p>The expansion<s count="2"/> of the British Empire led to cricket<s count="5"/> being played overseas and by the mid-19th century</p> 
</session>

我是XSLT的新手,我想不出任何逻辑我怎么能完成这项任务。 你能告诉我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:1)

xslt 1.0

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- template for s not directly preceded by s -->
    <xsl:template match="s[preceding-sibling::node()[1][not(self::s)]]">
        <s>
            <xsl:attribute name="count">
                <xsl:call-template name="count">
                    <xsl:with-param name="ctx" select="."/>
                    <xsl:with-param name="ret" select="1"/>
                </xsl:call-template>
            </xsl:attribute>
        </s>
    </xsl:template>

    <!-- do nothing with other s -->
    <xsl:template match="s[preceding-sibling::node()[1][self::s]]"/>

    <!-- calculate the number of adjacent s -->
    <xsl:template name="count">
        <xsl:param name="ctx"/>
        <xsl:param name="ret"/>

        <xsl:choose>
            <xsl:when test="$ctx/following-sibling::node()[1][self::s]">
                <xsl:call-template name="count">
                    <xsl:with-param name="ctx" select="$ctx/following-sibling::s[1]"/>
                    <xsl:with-param name="ret" select="$ret + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$ret"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

假设使用XSLT 2.0,您可以使用for-each-group select="node()" group-adjacent="boolean(self::s)"

解决这个问题
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="p[s]">
  <xsl:copy>
    <xsl:for-each-group select="node()" group-adjacent="boolean(self::s)">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
          <s count="{count(current-group())}"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="current-group()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>