C#XDocument加载多个根

时间:2013-08-12 11:49:26

标签: c# xml linq-to-xml

我有一个没有root的XML文件。我无法改变这一点。我正在尝试解析它,但XDocument.Load不会这样做。我试图设置ConformanceLevel.Fragment,但我仍然会抛出异常。有人有解决方案吗?

我尝试使用XmlReader,但事情搞砸了,无法让它正常工作。 XDocument.Load效果很好,但如果我有一个包含多个根的文件,则不会。

4 个答案:

答案 0 :(得分:18)

XmlReader本身支持读取xml片段 - 即

var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
using (var reader = XmlReader.Create("fragment.xml", settings))
{
  // you can work with reader just fine
}

但是XDocument.Load不支持读取碎片xml。

快速而肮脏的方法是在调用XDocument.Parse之前将节点包装在一个虚拟根目录下。像:

var fragments = File.ReadAllText("fragment.xml");
var myRootedXml = "<root>" + fragments + "</root>";
var doc = XDocument.Parse(myRootedXml);

此方法仅限于小型xml文件 - 因为您必须先将文件读入内存;并且连接大字符串意味着在内存中移动大对象 - 最好避免使用。

如果性能很重要,您应该通过XDocument逐个读取节点{@ 1}},如优秀的@ Martin-Honnen的回答(https://stackoverflow.com/a/18203952/2440262)所述

如果您使用理所当然XmlReader迭代有效xml并且性能很重要的API,则可以使用联接流方法:

XmlReader

MultiStream - 请参阅示例https://gist.github.com/svejdo1/b9165192d313ed0129a679c927379685

注意:using (var jointStream = new MultiStream()) using (var openTagStream = new MemoryStream(Encoding.ASCII.GetBytes("<root>"), false)) using (var fileStream = File.Open(@"fragment.xml", FileMode.Open, FileAccess.Read, FileShare.Read)) using (var closeTagStream = new MemoryStream(Encoding.ASCII.GetBytes("</root>"), false)) { jointStream.AddStream(openTagStream); jointStream.AddStream(fileStream); jointStream.AddStream(closeTagStream); using (var reader = XmlReader.Create(jointStream)) { // now you can work with reader as if it is reading valid xml } } 将整个xml加载到内存中。所以不要将它用于大文件 - 而是使用XDocument进行迭代,并通过XmlReader

将加载位加载为XElement

答案 1 :(得分:13)

.NET框架中唯一可以处理片段的内存中树表示是.NET的DOM实现中的XmlDocumentFragment,因此您需要创建一个XmlDocument和一个片段,例如< / p>

XmlDocument doc = new XmlDocument();
XmlDocumentFragment frag = doc.CreateDocumentFragment();
frag.InnerXml = stringWithXml; // for instance 
                               // frag.InnerXml = File.ReadAllText("fragment.xml");

或是XPathDocument,您可以使用将ConformanceLevel设置为Fragment的XmlReader创建一个:

XPathDocument doc;
using (XmlReader xr = 
                 XmlReader.Create("fragment.xml", 
                                   new XmlReaderSettings()
                                   {
                                       ConformanceLevel = ConformanceLevel.Fragment
                                    }))
{
  doc = new XPathDocument(xr);
}

// new create XPathNavigator for read out data e.g.
XPathNavigator nav = doc.CreateNavigator();

显然XPathNavigator是只读的。

如果您想使用LINQ to XML,那么我同意您需要创建一个XElement作为包装器的建议。但是,不要使用文件内容拉入字符串,而是可以将XNode.ReadFrom与XmlReader一起使用,例如

public static class MyExtensions
{
    public static IEnumerable<XNode> ParseFragment(XmlReader xr)
    {
        xr.MoveToContent();
        XNode node;
        while (!xr.EOF && (node = XNode.ReadFrom(xr)) != null)
        {
            yield return node;
        }
    }
}

然后

XElement root = new XElement("root", 
                             MyExtensions.ParseFragment(XmlReader.Create(
                                 "fragment.xml", 
                                 new XmlReaderSettings() {
                                 ConformanceLevel = ConformanceLevel.Fragment })));

这比将所有内容都读成字符串更有效,更有效。

答案 2 :(得分:1)

如果您想使用XmlDocument.Load(),则需要将内容包装在根节点中。

或者你可以尝试这样的事情......

while (xmlReader.Read())
{
    if (xmlReader.NodeType == XmlNodeType.Element)
    {
        XmlDocument d = new XmlDocument();
        d.CreateElement().InnerText = xmlReader.ReadOuterXml();
     }
}

答案 3 :(得分:0)

XML文档不能包含多个根元素。需要一个根元素。你可以做一件事。获取所有fragment元素并将它们包装到根元素中并使用XDocument进行解析。

这是人们可以想到的最好和最简单的方法。