【问题标题】:xslt parse XML string into variable and use Xpathxslt 将 XML 字符串解析为变量并使用 Xpath
【发布时间】:2025-12-16 18:15:01
【问题描述】:

我的(简化的)输入 XML 文件包含以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<main>
    <DATA_RECORD>
        <MESSAGE>&#60;pd&#62;&#10;    &#60;cdhead version&#61;&#34;13&#34;/&#62;&#10;&#60;/pd&#62;</MESSAGE>
    </DATA_RECORD>
</main>

MESSAGE 元素值是一个字符转义的 XML 实例。它表示以下 XML:

<pd>
    <cdhead version="13"/>
</pd>

我想对输入 XML 应用 xsl 转换,并以某种方式将 MESSAGE 内容解析为变量并使用 Xpath 表达式来访问其详细信息。
我尝试如下添加一个 javascript 函数,但脚本返回的对象显然是不正确的 DOM 子类(请参见下面的结果)。为了完整起见,我添加了一个额外的函数,它将 DOM 内容作为字符串返回。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ms="urn:schemas-microsoft-com:xslt"
    xmlns:my="http://example.com/my"
    exclude-result-prefixes="ms my">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <ms:script language="JScript" implements-prefix="my">
        <![CDATA[
        function parseToDOM (input) {
        var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
        doc.loadXML (input);
        return doc.documentElement;
        };
        function parseToXMLString (input) {
        var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
        doc.loadXML (input);
        return doc.documentElement.xml;
        };
        ]]>
    </ms:script>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="DATA_RECORD">
            <xsl:variable name="DOM"><xsl:copy-of select="my:parseToDOM (MESSAGE)"/></xsl:variable>
            <xsl:variable name="XML"><xsl:copy-of select="my:parseToXMLString (MESSAGE)"/></xsl:variable>

            <msg1><xsl:value-of select="$XML"/></msg1>
            <msg2><xsl:value-of select="$XML" disable-output-escaping="yes"/></msg2>
            <dom><xsl:copy-of select="$DOM"/></dom>
            <version><xsl:value-of select="$DOM/pd/cdhead/@version"/></version>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <msg1>&lt;pd&gt;
    &lt;cdhead version="13"/&gt;
&lt;/pd&gt;</msg1>
    <msg2><pd>
    <cdhead version="13"/>
</pd></msg2>
    <dom/>
    <version></version>
</root>

如何使 Jscript 函数返回允许使用 Xpath 的结果?
顺便问一下,是否有一些 XSLT 1.0 函数可以将转义的 XML 字符串解析为允许使用 Xpath 的结果?

添加

我一直在尝试一些变化并接近解决方案。首先,Altova XMLSpy 允许选择 xsl 处理器,上面是使用内置处理器时的结果。当然,我需要MSXML 6.0,并且在选择一个时,发生错误,因为我必须解析INPUT.TEXT。但是我只是在 javascript 中做了额外的事情之后才成功地在结果中使用了 Xpath 表达式。事实证明,虽然&amp;#60; 等被解析为&amp;lt; 等,但这还不足以得出正确的 DOM 结果。所以我首先求助于对输入字符串进行转义。
但我遇到了另一个障碍:下面的工作正常,但当我使用input.text 而不是下面的文字时,它就不行了。

请参阅下面的 xslt。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ms="urn:schemas-microsoft-com:xslt"
    xmlns:my="http://example.com/my"
    exclude-result-prefixes="ms my">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <ms:script language="JScript" implements-prefix="my">
        <![CDATA[
        function parseToDOM (input) {
            var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
            doc.loadXML (unescapeXML ('&#60;pd&#62;&#10;    &#60;cdhead version&#61;&#34;13&#34;/&#62;&#10;&#60;/pd&#62;'));
            //doc.loadXML (unescapeXML (input.text));
            return doc;
        };
        function unescapeXML (str) {
            var ostr = str;
            ostr = ostr.replace (/&#34;/g, '"');
            ostr = ostr.replace (/&#60;/g, '<');
            ostr = ostr.replace (/&#61;/g, '=');
            ostr = ostr.replace (/&#62;/g, '>');
            return ostr;
        };
        ]]>
    </ms:script>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="DATA_RECORD">
        <xsl:variable name="msg" select="my:parseToDOM (MESSAGE)"/>
        <tst><xsl:value-of select="$msg/pd/cdhead/@version"/></tst>
   </xsl:template>

</xsl:stylesheet>

现在结果

<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>

这正是我想要的。

但如上所述,当我注释文字的解析并改用输入时,如下所示:

//doc.loadXML (unescapeXML ('&#60;pd&#62;&#10;    &#60;cdhead version&#61;&#34;13&#34;/&#62;&#10;&#60;/pd&#62;'));
doc.loadXML (unescapeXML (input.text));

我收到以下错误(在 Altova XML Spy 中使用 MSXML 6.0 作为 xslt 解析器):

XSL transformation failed due to following error:

Microsoft JScript runtime error
'undefined' is null or not an object
line = 10, col = 3 (line is offset from the start of the script block).
Error returned from property or method call.

第一个 javascript replace 语句的点。

而且,IE9 也无法正确处理以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
  <DATA_RECORD>
    <MESSAGE>&#60;pd&#62;&#10;    &#60;cdhead version&#61;&#34;13&#34;/&#62;&#10;&#60;/pd&#62;</MESSAGE>
  </DATA_RECORD>
 </main>

当我在 IE9 中打开这个文件时(其中 test.xslt 是转换的版本,其中输入被忽略,而是处理文字,因此在 XML Spy 中是可以的),我收到一个处理错误:

XML5001: Applying Integrated XSLT Handling. 
XSLT8690: XSLT processing failed. 

为什么会这样?我该如何纠正?

【问题讨论】:

  • 你想在哪里使用这个?是在 .NET 代码中,还是在 IE 中?
  • 这是一个 XML Spy 转换,用于手动执行或从 XML 文件中引用 xslt,以便可以在 IE9 中打开 XML 文件。输入来自 Toad 查询结果保存,其中查询的列之一包含 XML 字符串。

标签: xslt dom internet-explorer-9 xslt-1.0 jscript


【解决方案1】:

从上面的ADDITION开始,我通过微调得到了一个解决方案。
为了避免不得不做input.text 并改用普通的input,xsl 必须包含通过应用 xslt string 函数将元素转换为字符串(我认为它已经是一个字符串,但显然情况并非如此)。此外,现在不再需要应用替换语句。
因此

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ms="urn:schemas-microsoft-com:xslt"
    xmlns:my="http://example.com/my"
    exclude-result-prefixes="ms my">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <ms:script language="JScript" implements-prefix="my">
        <![CDATA[
        function parseToDOM (input) {
            var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
            doc.loadXML (input);
            return doc;
        };
        ]]>
    </ms:script>

    <xsl:template match="/">
        <root>
            <xsl:apply-templates/>
        </root>
    </xsl:template>

    <xsl:template match="DATA_RECORD">
        <xsl:variable name="msg" select="my:parseToDOM (string(MESSAGE))"/>
        <tst><xsl:value-of select="$msg/pd/cdhead/@version"/></tst>
   </xsl:template>

</xsl:stylesheet>

作品:应用时

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<main>
  <DATA_RECORD>
    <MESSAGE>&#60;pd&#62;&#10;    &#60;cdhead version&#61;&#34;13&#34;/&#62;&#10;&#60;/pd&#62;</MESSAGE>
  </DATA_RECORD>
 </main>

结果是

<?xml version="1.0" encoding="UTF-8"?>
<root>
<tst>13</tst>
</root>

不幸的是,IE9 仍然无法通过引用的 XSLT 加载 XML;我发现了原因。
我必须勾选 Internet 选项/高级/安全/允许活动内容在我的电脑上的文件中运行 - 并重新启动 IE - 这使得 IE9 可以正确处理文件。当然,结果不是 html 意味着只能在 F12/Script 选项卡中查看结果,但这只是一个示例,我会将其合并到生成正确 html 的 xslt 中。

【讨论】: