XSLT将元素名称转换为Pascal大小写

时间:2016-03-04 14:11:10

标签: xml xslt

我有以下要求:

new FileInputStream("/path/on/my/system/Data.xml")

我需要将其转换为以下XML:

{{1}}

首选XSLT 1.0解决方案。

基本上,元素名称应从大写字母开始,每个字母在下划线应为大写后出现。然后删除下划线。 请注意,这只需要应用于元素名称而不是文本。

3 个答案:

答案 0 :(得分:4)

这在XSLT 1.0中有点工作:

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

<xsl:template match="*">
    <xsl:variable name="new-name">
        <xsl:call-template name="PascalCase">
            <xsl:with-param name="text" select="name()"/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:element name="{$new-name}">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template name="PascalCase">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="'_'"/>
    <xsl:param name="upper-case" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
    <xsl:param name="lower-case" select="'abcdefghijklmnopqrstuvwxyz'"/>

    <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
    <xsl:value-of select="translate(substring($token, 1, 1),  $lower-case, $upper-case)" />
    <xsl:value-of select="translate(substring($token, 2),  $upper-case, $lower-case)" />
    <xsl:if test="contains($text, $delimiter)">
        <!-- recursive call -->
        <xsl:call-template name="PascalCase">
            <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

请注意,这只会转换明确列出的字符。

答案 1 :(得分:1)

此解决方案比目前接受的答案略短且效率更高

在元素具有属性的情况下,它也能正常工作。

<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:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
 <xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>

  <xsl:template match="*">
    <xsl:variable name="vEName"><xsl:call-template name="PCase"/></xsl:variable>
    <xsl:element name="{$vEName}">
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

  <xsl:template name="PCase">
    <xsl:param name="pName" select="translate(name(), $vUpper, $vLower)"/>
    <xsl:if test="$pName">
      <xsl:variable name="vNextToken" select="substring-before(concat($pName, '_'), '_')"/>
      <xsl:value-of select=
      "concat(translate(substring($vNextToken,1,1), $vLower, $vUpper), 
              substring($vNextToken,2))"/>

      <xsl:call-template name="PCase">
        <xsl:with-param name="pName" select="substring-after($pName, '_')"/>
      </xsl:call-template>
    </xsl:if>    
  </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(提供的具有添加属性的文档):

<TAG_ONE x="y">
    <TAG_TWO>Abc</TAG_TWO>
    <TAG_THREE>Xyz</TAG_THREE>
</TAG_ONE>

产生了想要的正确结果

<TagOne x="y">
   <TagTwo>Abc</TagTwo>
   <TagThree>Xyz</TagThree>
</TagOne>

答案 2 :(得分:0)

使用非常复杂的XPath字符串串联子串,这是可能的。下面提供的实现只有在只有一个'_'下划线时才有效。对于更一般的情况,连接必须放在单独的命名模板中。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" method="xml" />
  <xsl:template match="node()[not(name()='')]">
    <xsl:variable name="elemName">
      <xsl:call-template name="toLower">
        <xsl:with-param name="str" select="name()" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:element name="{concat(substring-before(concat(substring(name(),1,1),substring($elemName,2)),'_'),concat(substring(substring-after(name(),'_'),1,1),substring(substring-after($elemName,'_'),2)))}">
      <xsl:apply-templates select="node() | @*" />
    </xsl:element>
  </xsl:template>
  <xsl:template name="toLower">
    <xsl:param name="str" />
    <xsl:value-of select="translate($str,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')" /> 
  </xsl:template>
</xsl:stylesheet>