在XSLT中将XML转换为转义文本

Fra*_*iao 26 xml xslt

如何使用XSLT将以下XML转换为转义文本?

资源:

<?xml version="1.0" encoding="utf-8"?>
<abc>
  <def ghi="jkl">
    mnop
  </def>
</abc>
Run Code Online (Sandbox Code Playgroud)

输出:

<TestElement>&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;abc&gt;&lt;def ghi="jkl"&gt;
    mnop
  &lt;/def&gt;&lt;/abc&gt;</TestElement>
Run Code Online (Sandbox Code Playgroud)

目前,我正在尝试以下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>
Run Code Online (Sandbox Code Playgroud)

.NET XslCompiledTransform输出的XSLT语句如下所示:

<?xml version="1.0" encoding="utf-8"?><TestElement>

    mnop

</TestElement>
Run Code Online (Sandbox Code Playgroud)

Pav*_*aev 37

您的代码以它的方式工作,因为它xsl:value-of检索节点集的字符串值.

要做你想做的事,我担心你必须明确地编码:

    <xsl:template match="/">
        <TestElement>
            <xsl:apply-templates mode="escape"/>
        </TestElement>
    </xsl:template>

    <xsl:template match="*" mode="escape">
        <!-- Begin opening tag -->
        <xsl:text>&lt;</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>&gt;</xsl:text>

        <!-- Content (child elements, text nodes, and PIs) -->
        <xsl:apply-templates select="node()" mode="escape" />

        <!-- Closing tag -->
        <xsl:text>&lt;/</xsl:text>
        <xsl:value-of select="name()"/>
        <xsl:text>&gt;</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>&lt;?</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>?&gt;</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;'">&amp;amp;</xsl:when>
                <xsl:when test="$head = '&lt;'">&amp;lt;</xsl:when>
                <xsl:when test="$head = '&gt;'">&amp;gt;</xsl:when>
                <xsl:when test="$head = '&quot;'">&amp;quot;</xsl:when>
                <xsl:when test="$head = &quot;&apos;&quot;">&amp;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>
Run Code Online (Sandbox Code Playgroud)

请注意,此解决方案忽略注释节点,并插入不必要的命名空间节点(因为namespace::轴将包括从父级继承的所有节点).但是,关于名称空间,结果引用的XML在语义上等同于您在回复中提供的示例(因为重复的重新声明并不会真正改变任何内容).

此外,这不会逃避<?xml ... ?>声明,因为它不存在于XPath 1.0数据模型中(它不是处理指令).如果您在输出中确实需要它,则必须手动插入它(并确保它指定的编码与XSLT处理器的序列化编码一致).


小智 17

您可以在CDATA部分中添加文本而不是转义.解析器将忽略CDATA部分内的文本,类似于它是否被转义.

你的例子看起来像这样

<TestElement>
<![CDATA[
<abc>
  <def ghi="jkl">
    mnop
  </def>
</abc>
]]>
</TestElement>
Run Code Online (Sandbox Code Playgroud)

使用以下XSLT片段:

<xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
 <xsl:copy-of select="/"/>
 <xsl:text disable-output-escaping="yes">]]</xsl:text>
 <xsl:text disable-output-escaping="yes">&gt;</xsl:text>
Run Code Online (Sandbox Code Playgroud)