XSLT 将一个元素替换为多个元素



我想用多个元素替换XML(大(中的元素,如下所示:

原始 XML:

<root>
  <cr>
   <id>1</id>
   <release>A</release>
  </cr>
  <cr>
   <id>2</id>
   <release>B</release>
  </cr>
</root>

我希望输出是:

<root>
  <cr>
   <id>1</id>
   <release>Aa</release>
   <release>Ab</release>
   <release>Ad</release>
  </cr>
  <cr>
   <id>2</id>
   <release>Bd</release>
   <release>Be</release>
  </cr>
</root>

原则是,每当有//release[text((='A'] 时,将元素替换为上面的三个,每当有//release[text((='B'] 时,将元素替换为上面的两个,依此类推。如果发布文本((是"C"或"D"或其他值,则它们保持相同的值。

我的尝试:

<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="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="//cr/release/text()">
    <xsl:if test=".='A'">
        <xsl:value-of select="Aa"/>
    </xsl:if>
</xsl:template>
</xsl:stylesheet>

它适用于一个 -> 一个替换,但如何做多个?多谢

这是一个完全通用且简短的 XSLT 1.0 解决方案。它使用映射 xml 文件,该文件指定每个所需版本的替换:

(请在此答案的末尾找到用 XSLT 2.0 编写的最终通用和简短的解决方案。

<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="vMap" select="document('mapping.xml')/*/*"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="release[. = document('mapping.xml')/*/release/@old]">
    <xsl:copy-of select="$vMap[@old = current()]/*"/>
  </xsl:template>
</xsl:stylesheet>

如果文件mapping.xml与转换(.xsl 文件(位于同一目录中,并且:

<map>
    <release old="A">
        <release>Aa</release>
        <release>Ab</release>
        <release>Ad</release>
    </release>
    <release old="B">
        <release>Ba</release>
        <release>Bb</release>
        <release>Bd</release>
    </release>
</map>

然后,当转换应用于此 XML 文档时

<root>
  <cr>
   <id>1</id>
   <release>A</release>
  </cr>
  <cr>
   <id>2</id>
   <release>B</release>
  </cr>
  <cr>
   <id>3</id>
   <release>C</release>
  </cr>
  <cr>
   <id>4</id>
   <release>D</release>
  </cr>
</root>

生成所需的正确结果

<root>
   <cr>
      <id>1</id>
      <release>Aa</release>
      <release>Ab</release>
      <release>Ad</release>
   </cr>
   <cr>
      <id>2</id>
      <release>Ba</release>
      <release>Bb</release>
      <release>Bd</release>
   </cr>
   <cr>
      <id>3</id>
      <release>C</release>
   </cr>
   <cr>
      <id>4</id>
      <release>D</release>
   </cr>
</root>

: 许多不同名称的元素可能会替换为相同的转换。

如果我们有这个映射文件

<map>
    <release old="A">
        <release>Aa</release>
        <release>Ab</release>
        <release>Ad</release>
    </release>
    <release old="B">
        <release>Ba</release>
        <release>Bb</release>
        <release>Bd</release>
    </release>
    <history old="p">
        <history>Pp</history>
        <history>Pq</history>
        <history>Pr</history>
    </history>
</map>

和这个源 XML 文档

<root>
  <cr>
   <id>1</id>
   <history>p</history>
   <release>A</release>
  </cr>
  <cr>
   <id>2</id>
   <history>q</history>
   <release>B</release>
  </cr>
  <cr>
   <id>3</id>
   <history>r</history>
   <release>C</release>
  </cr>
  <cr>
   <id>4</id>
   <history>t</history>
   <release>D</release>
  </cr>
</root>

那么这个转换:

<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="vMap" select="document('mapping.xml')/*/*"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="release[. = document('mapping.xml')/*/release/@old]">
    <xsl:copy-of select="$vMap[@old = current()]/*"/>
  </xsl:template>
  <xsl:template match="history[. = document('mapping.xml')/*/history/@old]">
    <xsl:copy-of select="$vMap[@old = current()]/*"/>
  </xsl:template>
</xsl:stylesheet>

当应用于上述 XML 文档时,会产生所需的结果 -- 其中映射和替换多个不同名称的元素:

<root>
   <cr>
      <id>1</id>
      <history>Pp</history>
      <history>Pq</history>
      <history>Pr</history>
      <release>Aa</release>
      <release>Ab</release>
      <release>Ad</release>
   </cr>
   <cr>
      <id>2</id>
      <history>q</history>
      <release>Ba</release>
      <release>Bb</release>
      <release>Bd</release>
   </cr>
   <cr>
      <id>3</id>
      <history>r</history>
      <release>C</release>
   </cr>
   <cr>
      <id>4</id>
      <history>t</history>
      <release>D</release>
   </cr>
</root>

最后:可以在 XSLT 2.0 中编写一个更短、更通用的转换:

<xsl:stylesheet version="2.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="vMap" select="document('mapping.xml')/*/*"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match=
   "*[. = $vMap[name() eq name(current())]/@old]">
    <xsl:copy-of select="$vMap[name() eq name(current()) and @old eq current()]/*"/>
  </xsl:template>
</xsl:stylesheet>

请注意:在此转换中没有硬编码的元素名称!

更大的优势是:我们可以修改转换,因此我们可以在调用转换时将映射文档的 URI 作为全局参数传递 - 因此我们可以有一个单一的通用转换,该转换适用于任何未知的预先映射。

只有这些是必需的更改

 <xsl:param name="pmapUrl" select="'file:///c:/temp/mapping.xml'"/>
 <xsl:variable name="vMap" select="document($pmapUrl)/*/*"/>

完整的转换(全局参数pmapUrl可以并且通常将由转换的调用者动态指定(:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:param name="pmapUrl" select="'file:///c:/temp/mapping.xml'"/>
 <xsl:variable name="vMap" select="document($pmapUrl)/*/*"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match=
   "*[for $name in name() 
        return
          . = $vMap[name() eq $name]/@old]">
    <xsl:copy-of select="$vMap[@old = current()]/*"/>
  </xsl:template>
</xsl:stylesheet>

试试这个方式:

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="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="release[.='A']">
    <release>Aa</release>
    <release>Ab</release>
    <release>Ad</release>
</xsl:template>
<xsl:template match="release[.='B']">
    <release>Bd</release>
    <release>Be</release>
</xsl:template>
</xsl:stylesheet>

测试输入

<root>
  <cr>
   <id>1</id>
   <release>A</release>
  </cr>
  <cr>
   <id>2</id>
   <release>B</release>
  </cr>  
  <cr>
   <id>3</id>
   <release>C</release>
  </cr>
</root>

结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <cr>
      <id>1</id>
      <release>Aa</release>
      <release>Ab</release>
      <release>Ad</release>
   </cr>
   <cr>
      <id>2</id>
      <release>Bd</release>
      <release>Be</release>
   </cr>
   <cr>
      <id>3</id>
      <release>C</release>
   </cr>
</root>

相关内容

  • 没有找到相关文章

最新更新