如何使用XSLT将以下XML转换为转义文本?
资源:
<?xml version="1.0" encoding="utf-8"?> <abc> <def ghi="jkl"> mnop </def> </abc>
输出:
<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 -a检索节点集的
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 :: axis将包括从父级继承的所有节点)。然而,关于命名空间,所引用的引用的XML将在语义上等同于您在回复中提供的示例(因为重复的重新声明确实不会改变任何内容)。
另外,这不会逃避<?xml??>声明,只是因为它不存在于XPath 1.0数据模型中(它不是处理指令)。如果您在输出中实际需要它,则必须手动插入(并确保其指定的编码与XSLT处理器的序列化编码一致)。