使用xslt更改xml中逗号分隔标记的格式?

时间:2014-02-19 21:00:07

标签: html xml xslt xslt-1.0

我有一个xml文档,其中包含逗号分隔的标签,如...

<?xml version="1.0" encoding="utf-8" ?>
<pages>
    <page>
        <tags>AAMC 2013, Learning Health System, Cost</tags>
    </page>
    <page>
        <tags>AAMC 2013, Cost, Innovation</tags>
    </page>
    <page>
        <tags>AAMC 2013, Cost, Innovation</tags>
    </page>
</pages>

是否有可能使用xslt更改xml以显示更像下面的代码,它分隔标记名称并计算标记被引用的次数?

<?xml version="1.0" encoding="utf-8" ?>
<pages>
    <page>
        <tag>
            <name>AAMC 2013</name>
            <amount>3</amount>
        </tag>
        <tag>
            <name>Learning Health System</name>
            <amount>1</amount>
        </tag>
        <tag>
            <name>Cost</name>
            <amount>3</amount>
        </tag>
     </page>
    <page>
        <tag>
            <name>AAMC 2013</name>
            <amount>3</amount>
        </tag>
        <tag>
            <name>Cost</name>
            <amount>3</amount>
        </tag>
        <tag>
            <name>Innovation</name>
            <amount>2</amount>
        </tag>
    </page>
    <page>
        <tag>
            <name>AAMC 2013</name>
            <amount>3</amount>
        </tag>
        <tag>
            <name>Cost</name>
            <amount>3</amount>
        </tag>
        <tag>
            <name>Innovation</name>
            <amount>2</amount>
        </tag>
    </page>
</pages> 

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

IIUC,这里有两项任务:

  1. 标记标记;

  2. 计算每个标签的出现次数。

  3. 第二个任务需要输出第一个任务作为输入 - 所以我们需要两次通过:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="sametag" match="token" use="." />
    
    <xsl:template match="/">
    <!-- first pass -->
    <xsl:variable name="tagnames">
        <xsl:for-each select="pages/page">
            <page>
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="string" select="tags" />
                </xsl:call-template>
            </page>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="tagnames-set" select="exsl:node-set($tagnames)" />
    <!-- second (final) pass -->
    <pages>
        <xsl:for-each select="$tagnames-set/page">
            <page>
            <xsl:for-each select="token">
                <tag>
                    <name><xsl:value-of select="." /></name>
                    <amount><xsl:value-of select="count(key('sametag', .))" /></amount>
                </tag>
            </xsl:for-each>
            </page>
        </xsl:for-each>
    </pages>
    </xsl:template>
    
    <xsl:template name="tokenize">
        <xsl:param name="string"/>
        <xsl:param name="delimiter" select="', '"/>
        <xsl:choose>
            <xsl:when test="contains($string, $delimiter)">
                <token><xsl:value-of select="substring-before($string, $delimiter)" /></token>
                <!-- recursive call -->
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="string" select="substring-after($string, $delimiter)" />
                    <xsl:with-param name="delimiter" select="$delimiter" />
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <token><xsl:value-of select="$string"/></token>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    </xsl:stylesheet>
    

    请注意,这需要EXSLT node-set()函数,XSLT 1.0处理器广泛支持该函数。如果您的处理器支持EXSLT tokenize()函数,那么您可以使用它而不是标记化模板。它的输出已经是一个节点集,因此可以大大简化样式表。