首页 > 解决方案 > 将元素的单个 XML 属性转换为子元素

问题描述

首先,我想对所有了解 XSLT 处理情况的人表示钦佩。

通常,我会在 StackOverflow 上找到一些满足我需要的示例,稍微调整一下,然后继续使用 C 编码:),但这次我被卡住了,不明白为什么事情不工作。

我在这里找到了足够接近的问题

我对其进行了修改以处理我需要的单个属性,并且它与原始问题中的 XML 示例一起按预期工作。

即我可以得到:

<sect id="5" heading="1">
</sect>

修改为:

<sect heading="1">
    <id>5</id>
</sect>

在这里使用示例

但是我的 XML 有点复杂,到目前为止发现了 2 个问题来处理它(都在上面的链接中给出):

  1. 我希望新元素首先放在原始元素之后,但是如果自由文本出现在原始元素之后,结果会有所不同,即新元素将在文本之后。
  2. 处理我修改的元素时出现问题,例如:

<TableCell>User input and actions: for example, type <bold>exit</bold>, click <bold>OK</bold>, press <bold>Alt+C</bold></TableCell>

将改为

<TableCell>User input and actions: for example, type , click , press <bold>exit</bold><bold>OK</bold><bold>Alt+C</bold></TableCell>

如果将同一行放在具有我正在修改的属性的元素之外,则它保持不变。仔细观察第二个问题,它似乎与第一个问题相同或相似,即自由文本放在元素之前,并且不保留原始顺序。

由于我无法理解 XSLT 中的处理顺序,我不知道如何修复它。对此或完全替代建议的任何帮助将不胜感激。

问候,伊利亚。

标签: xmlxslt

解决方案


首先将要复制的属性作为属性与一个应用模板(或简单地使用它们的副本)处理就足够了,然后将模板应用到 id 属性和任何子节点:

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

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*[not(name()='id')]"/>
      <xsl:apply-templates select="@id | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@id">
      <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/bEzkntb/7


推荐阅读