You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改XSL以在XML转换中保留处理指令?

保留XML处理指令并同步元素重命名的XSL改造

需求背景

通过图形工具生成的XSL采用for-each和copy-of语法实现XML映射转换,但无法处理源XML新增的下游专用处理指令。需改造XSL满足:

  • 复制元素时同步携带其与前一元素间的关联处理指令
  • 保留未关联到目标元素的处理指令
  • 元素重命名时同步更新对应处理指令的目标名称(如favorite→preference)

原有XSL示例

<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:template match="/root">
    <root>
      <xsl:for-each select="data">
        <data>
          <xsl:copy-of select="id" />
          <xsl:copy-of select="comment" />
          <detail>
            <xsl:for-each select="detail">
              <xsl:copy-of select="name" />
              <preference>
                <xsl:value-of select="favorite" />
              </preference>
            </xsl:for-each>
          </detail>
        </data>
      </xsl:for-each>
    </root>
  </xsl:template>

</xsl:stylesheet>

含处理指令的源XML示例

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <data>
    <?format-number id?>
    <id>123</id>
    <?xml-multiple comment?>
    <?format-string comment?>
    <comment>hello</comment>
    <?format-string comment?>
    <comment>goodbye</comment>
    <?format-string text?>
    <text>bar</text>
    <detail>
      <?format-string name?>
      <name>bob</name>
      <?format-string favorite?>
      <favorite>cake</favorite>
    </detail>
    <?xml-multiple colors?>
  </data>
</root>

预期转换结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <data>
    <?format-number id?>
    <id>123</id>
    <?xml-multiple comment?>
    <?format-string comment?>
    <comment>hello</comment>
    <?format-string comment?>
    <comment>goodbye</comment>
    <detail>
      <?format-string name?>
      <name>bob</name>
      <?format-string preference?>
      <preference>cake</preference>
    </detail>
    <?xml-multiple colors?>
  </data>
</root>

改造后的XSL实现

<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:key name="rename-map" match="rename" use="@from">
    <xsl:value-of select="@to"/>
  </xsl:key>
  <xsl:variable name="rename-rules">
    <rename from="favorite" to="preference"/>
  </xsl:variable>

  <!-- 匹配处理指令,根据重命名规则更新目标名称 -->
  <xsl:template match="processing-instruction()">
    <xsl:variable name="target" select="substring-after(., ' ')"/>
    <xsl:variable name="new-target" select="document('')//key('rename-map', $target)"/>
    <xsl:if test="$new-target != ''">
      <xsl:processing-instruction name="{name()}">
        <xsl:value-of select="substring-before(., ' ')"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="$new-target"/>
      </xsl:processing-instruction>
    </xsl:if>
    <!-- 无匹配重命名规则时直接复制 -->
    <xsl:if test="$new-target = ''">
      <xsl:copy-of select="."/>
    </xsl:if>
  </xsl:template>

  <!-- 匹配所有元素,先复制前面的处理指令,再处理元素本身 -->
  <xsl:template match="*">
    <!-- 复制当前元素之前、前一个元素之后的所有处理指令 -->
    <xsl:copy-of select="preceding-sibling::node()[not(self::*)][count(following-sibling::*) = count(following-sibling::*[generate-id()=generate-id(current())])]"/>
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- 复制属性 -->
  <xsl:template match="@*">
    <xsl:copy/>
  </xsl:template>

  <!-- 根节点处理逻辑 -->
  <xsl:template match="/root">
    <root>
      <xsl:for-each select="data">
        <data>
          <!-- 处理id元素及关联指令 -->
          <xsl:apply-templates select="id"/>
          <!-- 处理comment元素及关联指令 -->
          <xsl:apply-templates select="comment"/>
          <detail>
            <xsl:for-each select="detail">
              <!-- 处理name元素及关联指令 -->
              <xsl:apply-templates select="name"/>
              <!-- 处理favorite重命名为preference,同步处理指令 -->
              <xsl:apply-templates select="favorite">
                <xsl:with-param name="new-name" select="'preference'"/>
              </xsl:apply-templates>
            </xsl:for-each>
          </detail>
          <!-- 复制data下未关联到目标元素的处理指令 -->
          <xsl:copy-of select="processing-instruction()[not(following-sibling::*[name()='id' or name()='comment' or name()='detail'])]"/>
        </data>
      </xsl:for-each>
    </root>
  </xsl:template>

  <!-- 处理需要重命名的元素 -->
  <xsl:template match="favorite">
    <xsl:param name="new-name"/>
    <!-- 复制元素前的处理指令并更新目标名称 -->
    <xsl:apply-templates select="preceding-sibling::processing-instruction()[count(following-sibling::*) = count(following-sibling::*[generate-id()=generate-id(current())])]"/>
    <xsl:element name="{$new-name}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

改造说明

  1. 处理指令匹配模板:单独匹配处理指令,通过预定义的重命名映射更新指令中的目标元素名称,无映射则直接复制。
  2. 元素处理模板:复制元素前的关联处理指令,再递归处理元素内容,确保指令随元素同步复制。
  3. 重命名元素处理:针对需要重命名的元素(如favorite),先处理其关联的处理指令(更新目标名称),再生成新名称的元素。
  4. 孤立指令保留:在根节点处理逻辑中,复制未关联到任何目标元素的处理指令(如<?xml-multiple colors?>)。

内容的提问来源于stack exchange,提问作者sparty02

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 06:35:20