XSLT-преобразование с MSXML не использует правильную кодировку - PullRequest
3 голосов
/ 11 марта 2011

Я использую IXMLDOMDocument::transformNode из MSXML 3.0 для применения XSLT-преобразований.Каждое из преобразований имеет директиву xsl:output, в которой в качестве кодировки указывается UTF-8.Например,

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                ...
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:str="http://exslt.org/strings"
                xmlns:math="http://exslt.org/math"
                extension-element-prefixes="str math">
  <xsl:output encoding="UTF-8" indent="yes" method="xml" />
  ...
</xsl:stylesheet>

Однако преобразованный результат всегда равен UTF-16 (а атрибут кодирования говорит UTF-16).

<?xml version="1.0" encoding="UTF-16"?>

Это ошибка в MSXML?

По разным причинам я бы очень хотел получить UTF-8.Есть ли обходной путь?Или мне нужно преобразовать преобразованный результат в UTF-8 самостоятельно и исправить атрибут кодирования?

Обновление: Я решил проблему, приняв кодировку UTF-16 идобавление метки порядка байтов, которая удовлетворяет нижестоящих пользователей преобразованного результата, но мне все еще интересно, как получить UTF-8 вывод.

Ответы [ 3 ]

4 голосов
/ 11 марта 2011

Вы, вероятно, отправляете выходные данные в дерево DOM или в поток символов, а не в поток байтов. Если это так, то не MSXML выполняет кодирование, и что бы ни делало окончательное кодирование, он не знает о директиве xsl: output (или даже XSLT).

2 голосов
/ 21 марта 2011

В дополнение к тому, что сказал Майкл Кей (что, конечно, хорошо), вот пример JScript, как преобразовать в поток, используя сериализацию XSLT в процессе:

// command line args
var args = WScript.Arguments;
if (args.length != 3) {
    WScript.Echo("usage: cscript msxsl.js in.xml ss.xsl out.xml");
    WScript.Quit();
}
xmlFile = args(0);
xslFile = args(1);
resFile = args(2);

// DOM objects
var xsl = new ActiveXObject("MSXML2.DOMDOCUMENT.6.0");
var xml = xsl.cloneNode(false);

// source document
xml.validateOnParse = false;
xml.async = false;
xml.load(xmlFile);
if (xml.parseError.errorCode != 0)
    WScript.Echo ("XML Parse Error : " + xml.parseError.reason);

// stylesheet document
xsl.validateOnParse = false;
xsl.async = false;
xsl.resolveExternals = true;
//xsl.setProperty("AllowDocumentFunction", true);
//xsl.setProperty("ProhibitDTD", false);
//xsl.setProperty("AllowXsltScript", true);
xsl.load(xslFile);
if (xsl.parseError.errorCode != 0)
    WScript.Echo ("XSL Parse Error : " + xsl.parseError.reason);

// output object, a stream
var stream = WScript.createObject("ADODB.Stream");
stream.open();
stream.type = 1;
xml.transformNodeToObject( xsl, stream );
stream.saveToFile( resFile );
stream.close();

Вы можете проверить, используя этот вход:

<Urmel>
    <eins>Käse</eins>
    <deux>café</deux>
    <tre>supplì</tre>
</Urmel>

И эта таблица стилей:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output encoding="UTF-8"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Я думаю, вам будет легко адаптировать пример JScript для C ++.

1 голос
/ 21 марта 2011

Как вы заметили, все BSTR - это UTF-16. Тем не менее, я думаю, что Майкл Людвиг, возможно, что-то здесь. Вы пробовали использовать этот метод?

HRESULT IXMLDOMDocument::transformNodeToObject(
    IXMLDOMNode *stylesheet,
    VARIANT outputObject);

Вы должны иметь возможность просто использовать CreateStreamOnHGlobal, сохранить полученный ptr IStream в VARIANT и передать его в качестве параметра outputObject. Теоретически. Я на самом деле не пробовал это, хотя:)

...