我的XDeclaration在哪里?

16

由于某种原因,以下代码生成的 XML 不包含声明:

        XDocument xDocument = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
            new XElement("project",
                new XAttribute("number", project.ProjectNumber),
                new XElement("store",
                    new XAttribute("number", project.StoreNumber)
                ),

                // User Element
                new XElement("user", 
                    new XAttribute("owner-id", project.OwnerID ?? 0),
                    new XElement("email", new XCData(project.OwnerEmail ?? "")),
                    new XElement("project-name", new XCData(project.ProjectName ?? ""))
                ),

                // Nested Project Element
                new XElement("nested-project", 
                    new XAttribute("version", new Version(1, 0)),
                    new XElement("project", 
                        new XAttribute("version", new Version(1, 0)),
                        xProjectItems = new XElement("project-items")
                    ),
                    new XElement("price-per-part", project.PricePerPart),
                    new XElement("sheet-quantity", project.SheetQuantity),
                    new XElement("edge-length", project.EdgeLength),
                    new XElement("price", project.Price),
                    new XElement("status", project.Status),
                    xMaterialItems = new XElement("alternative-material-items"),
                    xProductItems = new XElement("project-product-items")
                )
            )
        );

        String strXML = xDocument.ToString();

之前已经生成过声明了,我是不是漏掉了什么显而易见的东西?

谢谢。

3个回答

26

当你使用其中一个XDocument.Save方法时,XDeclaration会被提供。例如:

var doc = new XDocument (
            new XDeclaration ("1.0", "utf-8", "yes"),
            new XElement ("test", "data")
        );

string path = Path.Combine(Path.GetTempPath(), "temp.xml");
doc.Save(path);
Console.WriteLine(File.ReadAllText(path));

或者你可以采用这种方法:

var sw = new StringWriter();
doc.Save(sw);
string result = sw.GetStringBuilder().ToString();
Console.WriteLine(result);

编辑:请注意,某些方法会将UTF-8的声明转换为UTF-16。如果你想强制它保持UTF-8,你需要使用这种不同的方法:

using (var mem = new MemoryStream())  
using (var writer = new XmlTextWriter(mem, System.Text.Encoding.UTF8))
{
    writer.Formatting = Formatting.Indented;
    doc.WriteTo(writer);
    writer.Flush();
    mem.Flush();
    mem.Seek(0, SeekOrigin.Begin);
    using (var reader = new StreamReader(mem))
    {
        var xml = reader.ReadToEnd();
        Console.WriteLine(xml);
    }
}

1
那很糟糕。不是你的解决方案(这很酷 - 我没想到你可以用 StringWriter 做到这一点)。微软这样做很糟糕。我没有将此 XML 保存到文件中,而是将其传递到流中。'XDocument' 和 'XElement' 之间有什么区别?我的意思是它们很相似,但应该有一些区别。如果有人不想在字符串中包含声明,那么可以使用:xMyDocument.Root.ToString(); - Jordan
@Jordan 我想推断的理由是 XDocument 代表整个文档,而 XElement 是 XML 片段。虽然如此,它们非常相似。 - Ahmad Mageed
哦,我知道它们在一般情况下有什么不同,但在LINQ to XML中,XDocument似乎只是一个不能包含的XElement - Jordan

3

文档没有明确说明xDocument.ToString()会输出XML声明,它只说:“返回此节点的缩进XML。”。

在我的测试中,我发现以下方法将输出声明:

使用Declaration属性上的ToString

string strXML = string.Concat(xDocument.Declaration.ToString(), "\r\n",
                              xDocument.ToString());

或者使用Save方法:
string strXml;
using(var ms = new MemoryStream())
{
    xDocument.Save(ms);
    ms.Position = 0;
    using(var sr = new StreamReader(ms))
    {
        strXml = sr.ReadToEnd();
    }
}

注意:我认为@Ahmad Mageed使用StringWriter的方法是正确的。与我的“Save”方法相同的思路,但更简短。 - rsbarro
我认为在需要强制编码时,采用我编辑中展示的较长方法可能更为合适。 - Ahmad Mageed

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接