xslt разбирает XML-строку в переменную и использует Xpath

Мой (упрощенный) входной 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>

Я хотел бы применить преобразование xsl к входному XML и каким-то образом разобрать содержимое 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. Но мне удалось использовать в результате выражения Xpath только после выполнения дополнительных действий в javascript. Выяснилось, что в то время как &#60; и тому подобное разбираются в &lt; и так далее, этого недостаточно для достижения правильного результата DOM. Поэтому я прибегнул к удалению входной строки первым.
Но я столкнулся с еще одной загвоздкой: где ниже работает нормально, это не так, когда я использую input.text вместо буквального ниже.

Смотрите ниже xsl t.

<?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 в качестве парсера xsl t):

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.

А также, 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. 

Почему все это и как я могу это исправить?

1 ответ

Решение

Начиная с ДОПОЛНЕНИЯ выше, я нашел решение, немного подстроив его.
Чтобы избежать необходимости делать input.text и использовать простой input вместо этого xsl должен содержать преобразование элемента в строку путем применения строковой функции 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 (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 все еще не может загрузить XML с указанным XSLT; и я понял почему.
Мне пришлось поставить галочку в пункте "Свойства обозревателя" / "Дополнительно" / "Безопасность" / "Разрешить запуск активного содержимого в файлах на моем компьютере", а также перезапустить IE. Это заставляет IE9 правильно обрабатывать файл. Конечно, результат отсутствия html означает, что результат можно просмотреть только на вкладке F12/Script, но это был всего лишь пример, и я включу его в xslt, который генерирует правильный html.

Другие вопросы по тегам