使用XSLT基于文本拆分XML元素

时间:2013-01-25 18:38:32

标签: xml xslt-2.0

我正在使用XSLT将XML文件转换为另一个XML文件。 XML文件包含如下元素:

<Course>
      <ID>1001</ID>
      <Seats>10</Seats>
      <Description>Department: CS , Faculty: XYZ</Description>
</Course>

现在XSLT中有什么方法可以生成如下所示的新XML文件:

<Course>
      <ID>1001</ID>
      <Seats>10</Seats>
      <Department> CS </Department> 
      <Faculty> XYZ</Faculty>
</Course>

我希望将描述元素拆分为两个不同的元素部门教师,这些元素基本上是用逗号分隔的内容。我使用XMLspy编写了我的XSLT。

提前谢谢。

1 个答案:

答案 0 :(得分:2)

这是一个可能的XSLT2解决方案,它基于身份转换和特定于Description元素的模板中的tokenize字符串函数。

一般的想法是先将描述字符串拆分为“,”然后将每个生成的子字符串拆分为“:”,只选择最后一部分。

<?xml version="1.0"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">

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

    <xsl:template match="Description">
        <xsl:variable name="tokens" select="fn:tokenize(text(),',')"/>
        <xsl:element name="Department"><xsl:value-of select="fn:normalize-space(fn:tokenize($tokens[1],':')[2])"/></xsl:element>
        <xsl:element name="Faculty"><xsl:value-of select="fn:normalize-space(fn:tokenize($tokens[2],':')[2])"/></xsl:element>
    </xsl:template>

</xsl:stylesheet>

调整normalize-space函数作为最后一步,去除前导/尾随空格;如果没有必要,就把这一点留下来。

警告:这里的假设是对于描述文本的格式是固定的(即部门和教师总是以相同的顺序出现。)此外,假设在描述元素中既不出现“:”也不出现“,”文本。

上述转换产生预期结果:

<?xml version="1.0" encoding="UTF-8"?><Course>
      <ID>1001</ID>
      <Seats>10</Seats>
      <Department>CS</Department>
      <Faculty>XYZ</Faculty>
</Course>

请注意,在内部运行纯文本结构信息并不能完全充分利用XML,这完全与结构有关,但我想这种格式不是你可以控制的。

根据评论进行更新:

下面列出了基于regular expression匹配的更强大的替代解决方案。在这种情况下,只重写与Department,Faculty模式匹配的Description元素;否则原始的Description元素将通过:

<?xml version="1.0"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions">

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

    <xsl:template match="Description">
        <xsl:analyze-string select="." regex="\s*Department:\s*(.+)\s*,\s*Faculty:\s*(.+)\s*">
            <xsl:matching-substring>
                <xsl:element name="Department"><xsl:value-of select="regex-group(1)"/></xsl:element>
                <xsl:element name="Faculty"><xsl:value-of select="regex-group(2)"/></xsl:element>
            </xsl:matching-substring>
            <xsl:non-matching-substring>
                <xsl:element name="Description"><xsl:copy/></xsl:element>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </xsl:template>

</xsl:stylesheet>

这里的关键思想是使用xsl:analyze-string通过XSLT regular expression测试是否找到了预期的模式,并在这种情况下捕获相应的值。如果未找到匹配项,则会复制Description元素的原始内容。

注意:将它与根元素集成在一起作为读者的练习(因为OP示例不显示Course元素适合的位置)。