XSLT 用多个元素替换一个元素
XSLT replacing one elements with multiple elements
我想用以下多个元素替换 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' ], 将元素替换为上面的两个等。如果发布 text() 是 "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
<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>
这是一个完全通用且简短的 XSLT 1.0 解决方案。它使用 映射 xml 文件指定每个需要的版本的替换:
(请在此答案的末尾找到 ultimately-generic 和用 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 文档时,会产生想要的结果 -- 其中不止一个 differently-named 元素被映射和替换:
<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>
我想用以下多个元素替换 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' ], 将元素替换为上面的两个等。如果发布 text() 是 "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
<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>
这是一个完全通用且简短的 XSLT 1.0 解决方案。它使用 映射 xml 文件指定每个需要的版本的替换:
(请在此答案的末尾找到 ultimately-generic 和用 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 文档时,会产生想要的结果 -- 其中不止一个 differently-named 元素被映射和替换:
<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>