使用XSLT将XML文件中的一个属性拆分为两个属性

时间:2013-05-28 07:56:00

标签: xml xslt split

我是XML / XSLT的新手。

我需要转换包含如下元素的xml文件:

<person name="John Smith" />
<person name="Mary Ann Smith" />

这样的事情:

<person firstname="John" lastname="Smith" />
<person firstname="Mary Ann" lastname="Smith" />

name 属性可以包含可变数量的单词,只有最后一个应该转到 lastname ,其余的转到 firstname 。< / p>

我正在尝试使用Linux上的XSLT和xsltproc来实现这一点,但欢迎任何其他简单的解决方案。

谢谢, 布鲁诺

1 个答案:

答案 0 :(得分:1)

XSLT 1.0(以及XPath 1.0)在其字符串操作函数方面受到一定限制。有substring-beforesubstring-after函数允许您在特定模式的第一次出现之前和之后提取给定字符串的子字符串,但是没有直接的方法在 last 出现时拆分一个字符串。你必须使用(尾部)递归模板

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <xsl:template match="person/@name">
    <xsl:call-template name="splitName"/>
  </xsl:template>

  <xsl:template name="splitName">
    <!-- start with nothing in $first and all the words in $rest -->
    <xsl:param name="first" select="''" />
    <xsl:param name="rest" select="." />

    <xsl:choose>
      <!-- if rest contains more than one word -->
      <xsl:when test="substring-after($rest, ' ')">
        <xsl:call-template name="splitName">
          <!-- move the first word of $rest to the end of $first and recurse.
               For the very first word this will add a stray leading space
               to $first, which we will clean up later. -->
          <xsl:with-param name="first" select="concat($first, ' ',
                                               substring-before($rest, ' '))" />
          <xsl:with-param name="rest" select="substring-after($rest, ' ')" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <!-- $rest is now just the last word of the original name, and $first
             contains all the others plus a leading space that we have to
             remove -->
        <xsl:attribute name="firstname">
          <xsl:value-of select="substring($first, 2)" />
        </xsl:attribute>
        <xsl:attribute name="lastname">
          <xsl:value-of select="$rest" />
        </xsl:attribute>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

示例:

$ cat names.xml
<people>
  <person name="John Smith" />
  <person name="Mary Ann Smith" />
</people>
$ xsltproc split-names.xsl names.xml
<?xml version="1.0"?>
<people>
  <person firstname="John" lastname="Smith"/>
  <person firstname="Mary Ann" lastname="Smith"/>
</people>

如果您不想要<?xml...?>行,请添加

<xsl:output method="xml" omit-xml-declaration="yes" />

到样式表的顶部,紧跟在打开的<xsl:stylesheet>标记之后。