Непосредственно используйте резервный символ, когда результат преобразования XSLT не представлен в его кодировке - PullRequest
0 голосов
/ 14 мая 2019

У нас есть набор таблиц стилей XSLT, которые выводят в «текст».Каждая таблица стилей определяет свою собственную выходную кодировку, которая отличается между таблицами стилей, например:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" indent="no" encoding="windows-1252"/>
    ...
</xsl:stylesheet>

Таблицы стилей снабжаются различными файлами данных XML, некоторые из которых могут иногда содержать символ, который не может быть представлен в кодировке.шаблон объявляет.
Когда это происходит, при преобразовании возникает исключение:

Невозможно перевести символ Unicode \ uXXXX по индексу N в указанную кодовую страницу.

Чтобы быстро воспроизвести:

XDocument schema = XDocument.Parse(
    @"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
        <xsl:output method='text' encoding='windows-1252'/>
        <xsl:template match='root'>
          <xsl:value-of select='.' />
        </xsl:template>
      </xsl:stylesheet>"
);

XDocument data = XDocument.Parse(
    @"<root>Ψ</root>"
);

XslCompiledTransform transformator = new XslCompiledTransform();
using (var xr = schema.CreateReader())
{
    transformator.Load(schema.CreateReader());
}

using (var output_stream = new System.IO.MemoryStream())
using (var xr = data.CreateReader())
{
    transformator.Transform(xr, null, output_stream);
    // Error: Unable to translate Unicode character \u03A8 at index 0 to specified code page.
}

Мы рады заменить случайного оскорбительного персонажа на запасной символ (обычно это ?).Проблема заключается в том, что преобразователь, по-видимому, игнорирует ReplacementFallback s в переданном Encoding и в любом случае вызывает исключение:

var xml_writer_settings = transformator.OutputSettings.Clone();
var original_encoging = xml_writer_settings.Encoding;

xml_writer_settings.Encoding = System.Text.Encoding.GetEncoding(
    original_encoging.CodePage,
    System.Text.EncoderReplacementFallback.ReplacementFallback,
    System.Text.DecoderReplacementFallback.ReplacementFallback
);

using (var output_stream = new System.IO.MemoryStream())
using (var xr = data.CreateReader())
using (var xw = XmlWriter.Create(output_stream, xml_writer_settings))
{
    transformator.Transform(xr, xw);
    // Same error anyway
}

Что работает, так это преобразование шаблона в Unicode, независимо от того, что он первоначально запрашивали затем перекодировать его в запрошенную кодировку:

var xml_writer_settings = transformator.OutputSettings.Clone();
var original_encoging = xml_writer_settings.Encoding;

var sb = new StringBuilder();

using (var output_stream = new System.IO.MemoryStream())
using (var xr = data.CreateReader())
using (var xw = XmlWriter.Create(sb, xml_writer_settings)) // When transforming to StringBuilder, it's always UTF-16
{
    transformator.Transform(xr, xw);

    var b = original_encoging.GetBytes(sb.ToString());  // Default fallback character is used automatically

    output_stream.Write(b, 0, b.Length);
}

, но это выглядит как двойная работа.

Есть ли способ заставить XslCompiledTransform напрямую использоватьрезервный символ для непредставимых символов без промежуточного шага Unicode?

1 Ответ

1 голос
/ 17 мая 2019

Я думаю, что в соответствии со спецификацией вы получаете ошибку: https://www.w3.org/TR/xslt-10/#section-Text-Output-Method говорит: «Если дерево результатов содержит символ, который не может быть представлен в кодировке, которую процессор XSLT использует для вывода, XSLT процессор должен сообщить об ошибке ". Если вы посмотрите на трассировку стека, то получите сложное взаимодействие некоторых реализаций XmlWriter и классов кодирования текста, но если я попытаюсь найти используемые классы в справочной документации по исходному коду .NET Framework, кажется, что реализация XmlWriter часть этого намеренно вызывает исключение. Поэтому, если вы не реализуете свой собственный XmlWriter, который обрабатывает регистр иначе, я думаю, вы не сможете напрямую писать с конкретным xsl:output encoding в TextWriter кодировки, которая не содержит используемого выходного символа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...