2013-04-29 38 views
0

我遇到的情况,我需要转换:使用XSLT来更改元素属性,缩短名字

<Hand id="left"> 
    <FingerOne>Thumb</FingerOne> 
    <FingerTwo>Pointer</FingerTwo> 
    <FingerThree>Middle</FingerThree> 
</Hand> 

要:

<Hand id="left" F1="Thumb" F2="Pointer" F3="Middle" /> 

我一直在使用这一块的XSLT转换嵌套的实体标记到属性中,这很好。虽然将元素移动到属性中,但我不确定如何将名称“FingerOne”更改为1,将“FingerTwo”更改为2等。

<xsl:for-each select="*"> 
    <xsl:attribute name="{name()}"> 
     <xsl:value-of select="text()"/> 
    </xsl:attribute> 
</xsl:for-each> 

我找到答案https://stackoverflow.com/a/8274527/857994它显示了如何使用基本上是地图做转换。尽管我似乎无法让它在我的文档中工作。

请注意,我正在尝试使用JAXP在Java的XSLT功能中进行构建。它似乎并不支持许多XSLT2.0功能,所以如果你能坚持使用XSLT1.0,我会非常感激。

回答

3

这里的一个自包含的选项,不需要任何外部XML文件。

当这个XSLT:

<Hand id="left"> 
    <FingerOne>Thumb</FingerOne> 
    <FingerTwo>Pointer</FingerTwo> 
    <FingerThree>Middle</FingerThree> 
</Hand> 

......想要的结果产生:

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

    <my:attributeNames> 
    <name original="FingerOne" new="F1"/> 
    <name original="FingerTwo" new="F2"/> 
    <name original="FingerThree" new="F3"/> 
    </my:attributeNames> 

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

    <xsl:template match="Hand/*"> 
    <xsl:attribute 
     name="{document('')/*/my:attributeNames/* 
          [@original = name(current())]/@new}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
    </xsl:template> 
</xsl:stylesheet> 

......是对所提供的XML应用

<Hand id="left" F1="Thumb" F2="Pointer" F3="Middle" /> 

说明:

  • 注元件的<my:attributeNames> “阵列”;此外,请注意这些元素中的“旧”和“新”值是如何包含在属性中的。

  • 这些值可通过使用document('')指令访问,该指令指示解析器从当前文档中收集元素。


可替代地,这里有一个不同的XSLT 1.0溶液。这可能是如果有更多的有用:

  • document('')是,由于某些原因,在你的环境中无法使用。

OR

  • 使用伪字典在你的XSLT似乎有点重手(和你愿意做一个小的假设)。

当这个XSLT:

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

    <xsl:variable name="vStartingChar" select="'F'" /> 

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

    <xsl:template match="Hand/*"> 
    <xsl:attribute 
     name="{concat($vStartingChar, count(preceding-sibling::*) + 1)}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
    </xsl:template> 
</xsl:stylesheet> 

......是针对相同的输入XML应用,想要的结果,再次产生:

<Hand id="left" F1="Thumb" F2="Pointer" F3="Middle" /> 

说明:

注意在XSLT的顶部定义的变量:

<xsl:variable name="vStartingChar" select="'F'" /> 

这提供了方便的机制来改变为新的属性的起始字符。如前所述,如果这种相同的模式继续下去(即,附加的属性将遵循相同的方案 - F4,F5等),该解决方案是更好的阴影,因为它不需要你更新元素的“数组” 。

1

如果你想要去的字典方法,你应该先创建一个名为dict.xml文件的字典:

<dict> 
    <entry name="FingerOne">F1</entry> 
    <entry name="FingerTwo">F2</entry> 
    <entry name="FingerThree">F3</entry> 
</dict> 

然后,你可以写这样的转变:

<xsl:variable name="dict" select="document('dict.xml')/dict"/> 

<xsl:template match="Hand"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates select="*" mode="map-to-attr"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*" mode="map-to-attr"> 
    <xsl:attribute name="{$dict/entry[@name=name(current())]}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template>