Unicode到Windows-1251使用XML(HTML)转换 - 转换

时间:2011-05-10 08:59:35

标签: c# html xml encoding xslt

我有XML文件,需要通过应用XSL Transformation来生成带有Windows-1251编码的HTML文件。问题是XSL -file的Unicode字符不会像“&#1171”那样转换为HTML Unicode转义序列。在XSL Transformation期间,只有“?”标志是写而不是他们。如何让XslCompiledTransform.Transform方法执行此转换?或者是否有任何方法使用HTML Unicode转义序列将HTML-string写入Windows-1251 HTML文件,以便我可以执行XSL转换为字符串,然后通过此方法写入使用Windows-1251编码和HTML的文件 - 所有unicode字符的转义(如转换(“ғ”))将返回“ғ ”)?

XmlReader xmlReader = XmlReader.Create(new StringReader("<Data><Name>The Wizard of Wishaw</Name></data>"));

XslCompiledTransform xslTrans = new XslCompiledTransform();
xslTrans.Load("sheet.xsl");

using (XmlTextWriter xmlWriter = new XmlTextWriter("result.html", Encoding.GetEncoding("Windows-1251")))
{
    xslTrans.Transform(xmlReader, xmlWriter); // it writes Windows-1251 HTML-file but does not escape unicode characters, just writes "?" signs
}

谢谢大家的帮助!

更新

我在XSL文件中的输出配置标记:

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

我现在甚至都不希望XSL满足我的需求。但我想知道我没有任何方法来检查字符是否可以被指定的编码接受。像

这样的东西
Char.IsEncodable('ғ', Encoding.GetEncoding('Windows-1251'))

我目前的解决方案是将所有大于127的字符(c> 127)转换为&amp; #dddd;转义字符串,但我的主管对解决方案不满意,因为生成的HTML文件的来源不可读。

5 个答案:

答案 0 :(得分:1)

请注意,XML既是数据模型又是序列化格式。数据可以使用与此数据序列化不同的字符集。

看起来问题的关键原因是序列化过程试图限制数据模型的字符集,而您希望设置序列化格式的字符集。我们有一个例子:<band>Motörhead</band><band>Mot&#246;rhead</band>是相同的XML文档。它们具有相同的结构和完全相同的数据。由于heavy metal umlaut数据的字符集是unicode(或大于ASCII的字符集)但是,因为使用了字符引用&#246;,所以字符集后一种序列化形式的文档是ASCII。为了处理这些数据,您的XML工具在两种情况下仍然需要知道unicode,但是当使用后者的序列化时,I / O和文件传输工具不需要知道unicode。

我的猜测是,通过告诉XMLTextWriter使用Windows-1251编码,它实际上可能会尝试将数据的字符集限制为Windows-1251中包含的字符通过丢弃此字符集之外的所有字符并改为编写?字符。

但是,由于您通过XSL转换生成XML文档,因此可以直接在XSLT文档中控制序列化的字符集。这是通过向xsl:output元素添加encoding属性来完成的。修改它看起来像这样

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" encoding="windows-1251"/>

现在,XSLT处理器负责将序列化减少到字符集,并为windows-1251中包含的数据中的所有字符输出字符引用。

如果您真正需要更改数据的字符集,则需要使用合适的字符转换库处理数据,该库可以猜出最合适的替换字符(例如ö - &gt; {{ 1}})。

答案 1 :(得分:0)

尝试使用替换规则来补充您的xsl文件

<xsl:value-of select="replace(.,'&#1171;','&amp;#1171;')"/>

您可能希望使用正则表达式模式来执行此操作:

<xsl:value-of select="replace(.,'&#(\d+);','&amp;#$1;')"/>

你的问题起源于xml解析器,它在转换发生之前用相应的unicode字符替换数字实体引用。因此未知的字符(分别为'?')  最终在您转换的文档中。

希望这有帮助,

最好的问候,

的Carsten

答案 2 :(得分:0)

正确的解决方案是以Unicode编码(例如UTF-8)编写文件,忘记CP-1251和所有其他遗留编码。

但我会假设这不是出于某种原因的选择。

我可以设计的最佳替代方法是在将字符串替换为XmlReader之前进行字符串替换。您应该使用Encoding类将字符串转换为CP-1251中的字节数组,并创建自己的解码器回退机制。然后,回退机制可以插入XML转义序列。这样你就可以处理CP-1251中没有的所有(也就是那些)字符。

然后,您可以将字节数组(在CP-1251中)转换为普通的.NET字符串(在UTF-16中)并将其传递给XmlReader。需要转义的值已经被转义,因此最终文件应该正确写入。

<强>更新

我刚刚意识到这种方法的缺陷。 XmlWriter将进一步逃脱&amp;字符为&amp;,因此转义本身将显示在最终文档中,而不是它们所代表的字符。

这可能需要一些非常复杂的解决方案!

另一个更新

忽略上次更新。由于您以XML格式读取字符串,因此应正确解释转义。这是我快速尝试发布而不是思考问题的结果!

我建议的解决方案应该可以正常工作。

答案 3 :(得分:0)

您是否尝试在xsl:output中指定编码? (http://www.w3schools.com/xsl/el_output.asp

答案 4 :(得分:0)

最安全且最具互操作性的方法是在xsl:output元素中指定encoding =“us-ascii”。大多数XSLT处理器都支持编写这种编码。

US-ASCII是一种完全安全的编码,因为它是UTF-8的兼容子集(您可以选择将发出的XML标记为具有“utf-8”编码,因为这也是正确的:这可以是通过为xsl:output指定omit-xml-declaration =“yes”并手动将“&lt;?xml version ='1.0'coding ='utf-8'?&gt;”声明添加到输出中来完成。

这种方法有效,因为当使用US-ASCII编码时,序列化器被迫使用XML的转义机制来处理超过U + 007F的字符,因此将它们作为数字字符引用发出(“&amp;#..... ;“形式”。

在处理需要非标准编码的环境时,生成这种XML通常是一种很好的防御技术,因为它完全符合并且在实践中甚至可以使用一些消耗错误的软件。