使用xslt将分号串分隔为xml元素

时间:2017-12-06 14:04:29

标签: xml xslt xslt-1.0

我已经转换了xml:

<import>
    <issue>
        <article>
            <languageVersion>
                <title>some title</title>
                <keywords>keyword1; keyword2; keyword3</keywords>
            </languageVersion>
        </article>
        <article>
            <languageVersion>
                <title>some title</title>
                <keywords>keyword1; keyword2; keyword3</keywords>
            </languageVersion>
        </article>
    </issue>
</import>

现在我想用xslt转换用分号分隔标签中的所有单词,所以目标xml会是这样的:

<import>
    <issue>
        <article>
            <languageVersion>
                <title>some title</title>
                <keywords>
                    <keyword>keyword1</keyword>
                    <keyword>keyword2</keyword>
                    <keyword>keyword3</keyword>
                </keywords>
            </languageVersion>
        </article>
        <article>
            <languageVersion>
                <title>some title</title>
                <keywords>
                    <keyword>keyword1</keyword>
                    <keyword>keyword2</keyword>
                    <keyword>keyword3</keyword>
                </keywords>
            </languageVersion>
        </article>
        <article>
    </issue>
</import>

如何使用XSLT转换执行此操作?我已经尝试使用there中的代码,但不幸的是代码正在破坏其余的xml元素:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="keywords">
        <keywords>
            <xsl:apply-templates/>
        </keywords>
    </xsl:template>
    <xsl:template match="keywords" name="split">
        <xsl:param name="pText" select="."/>
        <xsl:param name="pItemElementName" select="'keyword'"/>
        <xsl:if test="string-length($pText) > 0">
            <xsl:variable name="vNextItem" select=
      "substring-before(concat($pText, ';'), ';')"/>
            <xsl:element name="{$pItemElementName}">
                <xsl:value-of select="$vNextItem"/>
            </xsl:element>
            <xsl:call-template name="split">
                <xsl:with-param name="pText" select="substring-after($pText, ';')"/>
                <xsl:with-param name="pItemElementName" select="$pItemElementName"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:3)

您有两个匹配keywords的模板,如果它们具有相同的优先级,则在XSLT中被视为错误。根据规范...

  

XSLT处理器可能会发出错误信号;如果它没有发出信号   错误,它必须通过从匹配模板中选择来恢复   剩下的规则,即样式表中最后出现的规则。

因此,在您的情况下,它只是正在使用的第二个模板。

但是,您需要做的就是删除第二个模板上的“匹配”以使其只是一个命名模板,并更改第一个模板以直接调用命名模板。您还应该添加身份模板,以处理现有元素,然后您的工作将完成

试试这个XSLT

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

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

    <xsl:template match="keywords">
        <xsl:copy>
            <xsl:call-template name="split" />
        </xsl:copy>
    </xsl:template>

    <xsl:template name="split">
        <xsl:param name="pText" select="."/>
        <xsl:param name="pItemElementName" select="'keyword'"/>
        <xsl:if test="string-length($pText) > 0">
            <xsl:variable name="vNextItem" select=
      "substring-before(concat($pText, ';'), ';')"/>
            <xsl:element name="{$pItemElementName}">
                <xsl:value-of select="$vNextItem"/>
            </xsl:element>
            <xsl:call-template name="split">
                <xsl:with-param name="pText" select="substring-after($pText, ';')"/>
                <xsl:with-param name="pItemElementName" select="$pItemElementName"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>