XSLT将元素名称转换为Pascal命名法

3
我可以帮您翻译,以下是您的要求:

我有以下需求:

<TAG_ONE>
<TAG_TWO>Abc</TAG_TWO>
<TAG_THREE>Xyz</TAG_THREE>
</TAG_ONE>

我需要将这个转换为以下XML:

<TagOne>
<TagTwo>Abc</TagTwo>
<TagThree>Xyz</TagThree>
</TagOne>

首选XSLT 1.0解决方案。

基本上,元素名称应以大写字母开头,下划线后的每个字母都应大写。然后删除下划线。请注意,这仅应用于元素名称,而不应用于文本。

3个回答

5

这是一些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>

请注意,这只会转换显式列出的字符。

好的答案,虽然我会将模板应用于"node() | @*",以防万一有任何属性,但由于OP的要求中没有属性,这可能是不必要的。 - Flynn1179

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>

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>

michael.hor257的方法是一种更通用的解决方案。 - zx485
以下提供的实现仅在有0或1个下划线'_'时有效。我相信它只在存在恰好一个分隔符时有效。 - michael.hor257k
是的,我在答案中已经包含了那个。 - zx485

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接