如何使用 XSLT 将以下 XML 转换为转义文本?
Source:
<?xml version="1.0" encoding="utf-8"?>
<abc>
<def ghi="jkl">
mnop
</def>
</abc>
Output:
<TestElement><?xml version="1.0" encoding="utf-8"?><abc><def ghi="jkl">
mnop
</def></abc></TestElement>
目前,我正在尝试以下 XSLT,但它似乎无法正常工作:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" />
<xsl:template match="/">
<xsl:variable name="testVar">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:variable>
<TestElement>
<xsl:value-of select="$testVar"/>
</TestElement>
</xsl:template>
</xsl:stylesheet>
.NET XslCompiledTransform 的 XSLT 语句输出如下:
<?xml version="1.0" encoding="utf-8"?><TestElement>
mnop
</TestElement>
您的代码按照它的方式工作是因为xsl:value-of
检索字符串值 http://www.w3.org/TR/xpath#dt-string-value的节点集。
为了做你想做的事,恐怕你必须明确地编码:
<xsl:template match="/">
<TestElement>
<xsl:apply-templates mode="escape"/>
</TestElement>
</xsl:template>
<xsl:template match="*" mode="escape">
<!-- Begin opening tag -->
<xsl:text><</xsl:text>
<xsl:value-of select="name()"/>
<!-- Namespaces -->
<xsl:for-each select="namespace::*">
<xsl:text> xmlns</xsl:text>
<xsl:if test="name() != ''">
<xsl:text>:</xsl:text>
<xsl:value-of select="name()"/>
</xsl:if>
<xsl:text>='</xsl:text>
<xsl:call-template name="escape-xml">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<xsl:text>'</xsl:text>
</xsl:for-each>
<!-- Attributes -->
<xsl:for-each select="@*">
<xsl:text> </xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>='</xsl:text>
<xsl:call-template name="escape-xml">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<xsl:text>'</xsl:text>
</xsl:for-each>
<!-- End opening tag -->
<xsl:text>></xsl:text>
<!-- Content (child elements, text nodes, and PIs) -->
<xsl:apply-templates select="node()" mode="escape" />
<!-- Closing tag -->
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:template>
<xsl:template match="text()" mode="escape">
<xsl:call-template name="escape-xml">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template match="processing-instruction()" mode="escape">
<xsl:text><?</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text> </xsl:text>
<xsl:call-template name="escape-xml">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
<xsl:text>?></xsl:text>
</xsl:template>
<xsl:template name="escape-xml">
<xsl:param name="text"/>
<xsl:if test="$text != ''">
<xsl:variable name="head" select="substring($text, 1, 1)"/>
<xsl:variable name="tail" select="substring($text, 2)"/>
<xsl:choose>
<xsl:when test="$head = '&'">&amp;</xsl:when>
<xsl:when test="$head = '<'">&lt;</xsl:when>
<xsl:when test="$head = '>'">&gt;</xsl:when>
<xsl:when test="$head = '"'">&quot;</xsl:when>
<xsl:when test="$head = "'"">&apos;</xsl:when>
<xsl:otherwise><xsl:value-of select="$head"/></xsl:otherwise>
</xsl:choose>
<xsl:call-template name="escape-xml">
<xsl:with-param name="text" select="$tail"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
请注意,此解决方案忽略注释节点,并插入不必要的命名空间节点(如namespace::
轴将包括从父级继承的所有节点)。然而,关于命名空间,生成的引用 XML 在语义上与您在回复中提供的示例等效(因为这些重复的重新声明并没有真正改变任何内容)。
另外,这也无法逃脱<?xml ... ?>
声明,只是因为它不存在于 XPath 1.0 数据模型中(它不是处理指令)。如果您确实在输出中需要它,则必须手动插入它(并确保它指定的编码与 XSLT 处理器的序列化编码一致)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)