0

我有一个需要转换的场景:

<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,我将不胜感激。

4

2 回答 2

3

这是一个独立的选项,不需要任何外部 XML 文件。

当这个 XSLT:

<?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">
  <FingerOne>Thumb</FingerOne>
  <FingerTwo>Pointer</FingerTwo>
  <FingerThree>Middle</FingerThree>
</Hand>

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

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

解释:

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

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


或者,这里有一个不同的 XSLT 1.0 解决方案。如果出现以下情况,它可能会更有用:

  • document('')由于某种原因,在您的环境中不可用。

或者

  • 在您的 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'" />

这提供了一种方便的机制来更改新属性的起始字符。如前所述,如果继续使用相同的模式(即,附加属性将遵循相同的方案 - F4F5等),则此解决方案的着色效果更好,因为它不需要您更新元素的“数组”。

于 2013-04-30T01:33:52.810 回答
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>
于 2013-04-30T00:18:55.067 回答