如何用简洁XSLT修改XML元素并保留其余标签结构?
问题:修改指定XML元素同时保留原有结构的XSLT实现
需求是将所有<price>元素内容改为“i win”,但现有XSLT转换后非<price>的标签全部被移除,问是否无需为每个标签编写模板就能修改指定元素并保留原有XML结构?
原始XML文档
<bookstore> <book genre="autobiography" publicationdate="1981" ISBN="1-861003-11-0"> <title>The Autobiography of Benjamin Franklin</title> <author> <first-name>Benjamin</first-name> <last-name>Franklin</last-name> </author> <price>8.99</price> </book> <book genre="novel" publicationdate="1967" ISBN="0-201-63361-2"> <title>The Confidence Man</title> <author> <first-name>Herman</first-name> <last-name>Melville</last-name> </author> <price>11.99</price> </book> <book genre="philosophy" publicationdate="1991" ISBN="1-861001-57-6"> <title>The Gorgias</title> <author> <name>Plato</name> </author> <price>9.99</price> </book> </bookstore>
现有XSLT文件
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <xsl:template match = "/bookstore/book/price"> <price>i win</price> </xsl:template> </xsl:stylesheet>
VB.NET执行代码
Module Module1 Sub Main() Dim xslt = New XslCompiledTransform dim curDir = My.Computer.FileSystem.CurrentDirectory xslt.Load(curDir & "\testtransform.xsl") xslt.Transform(curDir & "\testinv2.xml",curDir & "\outinv.xml") End Sub End Module
转换后输出结果
<?xml version="1.0" encoding="utf-8"?> The Autobiography of Benjamin Franklin Benjamin Franklin <price>i win</price> The Confidence Man Herman Melville <price>i win</price> The Gorgias Plato <price>i win</price>
解答
完全可以不用为每个标签单独编写模板,问题根源在于XSLT的默认模板行为:
- 元素和根节点的默认模板会递归处理子节点,但不会复制元素本身,仅输出文本内容
- 文本节点的默认模板会直接输出文本
现有XSLT只定义了<price>的匹配模板,其余元素均走默认模板,导致标签被丢弃,仅保留文本。
要保留原有结构,只需添加身份模板——它会复制所有未被自定义模板匹配的节点(包括元素、属性、文本等),同时让自定义模板处理<price>元素:
修改后的XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <!-- 身份模板:复制所有未被自定义模板匹配的节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 自定义模板:修改price元素内容 --> <xsl:template match="price"> <price>i win</price> </xsl:template> </xsl:stylesheet>
说明
match="@*|node()"匹配所有属性(@*)和各类节点(元素、文本、注释等)<xsl:copy>复制当前节点本身,<xsl:apply-templates>递归处理子节点,完整保留原有XML结构- 自定义
<price>模板优先级高于身份模板,会覆盖处理所有<price>元素,将内容替换为“i win”
使用该XSLT转换后,所有非<price>标签都会被保留,仅<price>元素内容被修改。
内容的提问来源于stack exchange,提问作者gist076923
相关产品推荐
相关产品推荐

