如何在XML属性值中处理'\ t'字符?

时间:2012-09-04 09:29:56

标签: c# .net xml

我似乎在.Net 3.5中的各种XML实现之间发现了一些不一致的东西,而且我很难找到名义上正确的。

这个问题实际上很容易重现:

  1. 使用包含'\ t'字符的文本元素创建一个简单的xml文档,并为其指定一个包含'\ t'字符的属性:

    var xmlDoc = new XmlDocument { PreserveWhitespace = false, };
    xmlDoc.LoadXml("<test><text attrib=\"Tab'\t'space' '\">Tab'\t'space' '</text></test>");
    xmlDoc.Save(@"d:\TabTest.xml");
    

    注意:这意味着XmlDocument本身对属性值中的'\ t'字符非常满意。

  2. 使用新的XmlTextReader加载文档:

    var rawFile = XmlReader.Create(@"D:\TabTest.xml");
    var rawDoc = new XmlDocument();
    rawDoc.Load(rawFile);
    
  3. 使用XmlReader.Create:

    加载文档
    var rawFile2 = new XmlTextReader(@"D:\TabTest.xml");
    var rawDoc2 = new XmlDocument();
    rawDoc2.Load(rawFile2);
    
  4. 比较调试器中的文档:

    (rawDoc).InnerXml   "<test><text attrib=\"Tab' 'space' '\">Tab'\t'space' '</text></test>"   string
    (rawDoc2).InnerXml  "<test><text attrib=\"Tab'\t'space' '\">Tab'\t'space' '</text></test>"  string
    
  5. 使用新的XmlTextReader读取的文档是我所期望的,文本值和属性值中的'\ t'都符合预期。 但是,如果查看XmlReader.Create读取的文档,您会发现属性值中的'\ t'字符已转换为' '字符。

    什么...... !! : - )

    经过一段谷歌搜索,我发现我可以将'\ t'编码为'&amp;#x9;' - 如果我在示例XML中使用此代替'\ t',则两个阅读器都按预期工作。

    现在Altova XmlSpy和其他各种XML阅读器似乎对属性值中的'\ t'字符非常满意,我的问题是处理这个问题的正确方法是什么?

    我是否应该使用在属性值中编码的'\ t'字符来编写XML文件,例如XmlReader.Create期望或其他XML工具是否正确,'\ t'字符是否有效且XmlReader.Create是否已损坏?

    我应该采用哪种方式解决此问题?

4 个答案:

答案 0 :(得分:2)

可能与属性值规范化有关。对于CDATA属性,需要XML解析器以空格替换属性值中的换行符和制表符,除非它们以转义形式写为字符引用。

答案 1 :(得分:1)

乍一看似乎XmlTextReader 符合W3C建议。请参阅the recommendation中有关属性值规范化的部分,特别是

  

对于空格字符(#x20,#xD,#xA,#x9),请在标准化值后附加空格字符(#x20)。

因此,您不期望的行为(看到空格而不是标签)实际上是推荐的正确行为。

我不知道为什么XmlTextReader以这种方式表现(文档中没有任何内容),但是您似乎已经确定了正确的解决方法 - 将属性编码为&#x9; 。在这种情况下,规范化字符串将包含制表符字符本身。

答案 2 :(得分:1)

结帐XmlReaderSettings.ComformanceLevel。特别是,这个描述:

  

请注意,默认情况下,Create方法创建的XmlReader对象比XmlTextReader类更兼容。以下是在XmlTextReader上未启用的一致性改进,但默认情况下可在Create方法创建的读取器上使用

答案 3 :(得分:1)

@all:感谢您的所有答案和评论。

似乎Justin和Michael Kay是正确的,并且应根据W3C XML规范对空白区域进行编码,问题是大量的MS实现不符合此要求。

在我的情况下,除了XML规范之外,我真正想要的是正确地保持属性值 - 即保存的值应该是读取的值。

答案是在第一时间保存XML文件时强制使用通过使用XmlWriter.Create方法创建的XmlWriter。

虽然Dataset和XmlDocument都提供了保存/写入机制,但是当它们以默认形式使用时,它们都没有正确编码属性中的空格。但是,如果我强制它们使用手动创建的XmlWriter,则会应用正确的编码并将其写入文件。

因此原始文件保存代码变为:

var xmlDoc = new XmlDocument { PreserveWhitespace = false, };
xmlDoc.LoadXml("<test><text attrib=\"Tab'\t'space' '\">Tab'\t'space' '</text></test>");

using (var xmlWriter = XmlWriter.Create(@"d:\TabTest.Encoded.xml"))
{
    xmlDoc.Save(xmlWriter);
}

然后,此编写器以对称方式正确编码空白区域,以便XmlReader.Create读取器在不更改属性值的情况下进行读取。

这里要注意的另一件事是,这个解决方案完全封装了我的代码编码,因为读写器在读写时透明地执行编码和解码。