2013-08-12 11 views
15

Ich habe eine XML-Datei ohne Root. Ich kann das nicht ändern. Ich versuche es zu analysieren, aber XDocument.Load wird es nicht tun. Ich habe versucht, ConformanceLevel.Fragment einzustellen, aber ich bekomme immer noch eine Ausnahme geworfen. Hat jemand eine Lösung dafür?C# XDocument Laden mit mehreren Wurzeln

Ich versuchte mit XmlReader, aber die Dinge sind durcheinander und kann es nicht richtig funktionieren. XDocument.Load funktioniert gut, aber wenn ich eine Datei mit mehreren Wurzeln habe, tut es das nicht.

+1

'XDocument.Load' funktioniert nicht, da diese Art von Datei kein gültiges XML-Dokument ist. – MarcinJuraszek

+0

Können Sie den Code posten, den Sie bisher ausprobiert haben? – christiandev

+0

Andere Frage, gleiche Antwort: http://StackOverflow.com/A/9378442 – dtb

Antwort

14

XmlReader selbst tut Unterstützung Lesen von XML-Fragment - d.h.

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

XDocument.Load jedoch nicht das Lesen von fragmentierten XML-Unterstützung.

Schnell und schmutzig ist es, die Knoten unter einem virtuellen Stamm zu wickeln, bevor Sie die XDocument.Parse aufrufen. Wie:

Dieser Ansatz ist auf kleine XML-Dateien beschränkt - wie Sie Datei in den Speicher zuerst lesen müssen; und das Verketten großer Zeichenketten bedeutet das Bewegen großer Objekte im Speicher - was am besten vermieden wird.

Wenn Leistung zählt, sollten Sie Knoten in XDocument one-by-one über XmlReader als in ausgezeichnetem erklärt @ Martin-Honnen ‚s Antwort (https://stackoverflow.com/a/18203952/2440262)

liest Wenn Sie API verwenden, die für selbstverständlich, dass XmlReader Iterierten nimmt über gültige xML und Leistung zählt, können Sie beigetreten-Stream-Ansatz verwenden, anstatt:

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 
    } 
} 

MultiStream- - siehe zum Beispiel https://gist.github.com/svejdo1/b9165192d313ed0129a679c927379685

Hinweis: XDocument lädt die gesamte XML in den Speicher. So tut es nicht für große Dateien verwenden - stattdessen verwenden XmlReader für Iteration und Last nur die knusprigen Bits als XElement über XNode.ReadFrom(...)

+6

Die Verwendung von 'XDocument.Parse()' sollte die Notwendigkeit zum Umbrechen der Zeichenfolge in einem 'StringReader' eliminieren. – CoderDennis

0

XML-Dokument kann nicht mehr als ein Stammelement hat. Ein Wurzelelement ist erforderlich. Sie können eine Sache tun. Holen Sie alle fragment Elemente und wickeln Sie sie in ein Wurzelelement und analysieren Sie es mit XDocument.

Dies wäre der beste und einfachste Ansatz, den man sich vorstellen kann.

1

Wenn Sie XmlDocument.Load() verwenden möchten, müssen Sie den Inhalt in einen Stammknoten einfügen.

oder man könnte so etwas wie dieses versuchen ...

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

Der einzige In-Memory-Baum-Darstellungen in dem .NET-Framework, die mit Fragmenten sind die XmlDocumentFragment in .NET die DOM-Implementierung umgehen können, so dass Sie müssten um ein XmlDocument und ein Fragment mit z

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

oder ist XPathDocument wo Sie eine erstellen können ein XmlReader mit ConformanceLevel mit auf Fragment:

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(); 

Offensichtlich XPathNavigator ist schreibgeschützt.

Wenn Sie LINQ zu XML verwenden möchten, stimme ich den gemachten Vorschlägen zu, dass Sie ein XElement als Wrapper erstellen müssen. Anstatt eine Zeichenkette mit dem Dateiinhalt einzuziehen, könnten Sie jedoch XNode.ReadFrom mit einem XmlReader verwenden, z.

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; 
     } 
    } 
} 

dann

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

, die besser funktionieren könnte und effizienter als alles in einen String zu lesen.

Verwandte Themen