如何在XML中解释带有CDATA和空格的文本节点?

时间:2014-12-15 07:50:28

标签: c# xml

System.Xml解析功能在我的商店中有一些惊喜,我想知道如何解释以下 ,或者如果这是"直到实现" :

版本1

<root><elem>
    <![CDATA[MyValue]]>
</elem></root>

版本2:

<root><elem>
    -<![CDATA[MyValue]]>-
</elem></root>

应该elem的值还是可以这取决于解析它的实现,我应该只处理它?

我预计(首先)在两种情况下,开始/结束节点和第一个非空白字符之间的所有空格都将被忽略。事实并非如此,但如果不这样做,我至少会期望从不被忽略,但事实并非如此。请参阅下面的完整repro以了解我的期望。


详细说明......

我测试时有两个案例让我难过:

  • XDocument.Parse将突然开始在示例2中包含\n\t空格,而在示例1中忽略它。
  • XDocument.Loadnew XmlReaderSettings {IgnoreWhitespace = true}的行为相似。

是什么给出的?这只是实现(根据我的口味)古怪,和/或这是指定的行为吗?

这里完全符合我的期望(来自NuGet的最新NUnit软件包的新C#类库项目):

[TestFixture]
public class XmlTests
{
    public static XDocument ParseDocument(string input)
    {
        return XDocument.Parse(input);
    }

    public static XDocument LoadDocument(Stream stream)
    {
        var xmlReader = XmlReader.Create(stream, new XmlReaderSettings() { IgnoreWhitespace = false }); // Default
        return XDocument.Load(xmlReader);
    }

    public static XDocument LoadDocument_IgnoreWhitespace(Stream stream)
    {
        var xmlReader = XmlReader.Create(stream, new XmlReaderSettings() { IgnoreWhitespace = true });
        return XDocument.Load(xmlReader);
    }

    const string example1 = "<root><elem>\n\t<![CDATA[MyValue]]>\n</elem></root>";
    const string example2 = "<root><elem>\n\t-<![CDATA[MyValue]]>-\n</elem></root>";

    [Test]
    public void A_Parsing_Example1_WorksAsExpected()
    {
        var doc = ParseDocument(example1);
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("MyValue"));
    }

    [Test]
    public void B_Loading_Example1_WorksAsExpected()
    {
        var doc = LoadDocument(new MemoryStream(Encoding.UTF8.GetBytes(example1)));
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("\n\tMyValue\n"));
    }

    [Test]
    public void C_LoadingWithIgnoreWhitespace_Example1_WorksAsExpected()
    {
        var doc = LoadDocument_IgnoreWhitespace(new MemoryStream(Encoding.UTF8.GetBytes(example1)));
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("MyValue"));
    }

    [Test]
    public void D_Parsing_Example2_WorksAsExpected()
    {
        var doc = ParseDocument(example2);
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("-MyValue-"));
    }

    [Test]
    public void E_Loading_Example2_WorksAsExpected()
    {
        var doc = LoadDocument(new MemoryStream(Encoding.UTF8.GetBytes(example2)));
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("\n\t-MyValue-\n"));
    }

    [Test]
    public void F_LoadingWithIgnoreWhitespace_Example2_WorksAsExpected()
    {
        var doc = LoadDocument_IgnoreWhitespace(new MemoryStream(Encoding.UTF8.GetBytes(example2)));
        var element = doc.Descendants("elem").Single();
        Assert.That(element.Value, Is.EqualTo("MyValue"));
    }
}

1 个答案:

答案 0 :(得分:2)

CDATAs很难。它们不会被解析器更改(读取)。不允许他们包含无效字符或]]>。但是,某些实现会更改它们以生成有效的XML输出(写入)。

elem的内容取决于解析器,是否忽略空白节点。 elem有3个子节点。

  1. 包含内容&#34; \n\t&#34;
  2. 的空白文字节点
  3. 包含内容&#34; MyValue&#34;
  4. 的cdata部分节点
  5. 包含内容&#34; \n&#34;
  6. 的空白文字节点

    所以就像你注意到如果忽略空白节点,只剩下cdata。在第二个例子中,结果会有所不同(如果已修复)。

    1. 包含内容&#34; \n\t-&#34;
    2. 的文字节点
    3. 包含内容&#34; MyValue&#34;
    4. 的cdata部分节点
    5. 包含内容&#34; -\n&#34;
    6. 的文字节点

      第一个和第三个节点现在有非空白内容( - )。它们不再是空白节点,根据选项不会被忽略。