У нас есть набор таблиц стилей 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?