ルートのないXMLファイルがあります。これは変更できません。解析しようとしていますが、XDocument.Load
では解析できません。 ConformanceLevel.Fragment
を設定しようとしましたが、それでも例外がスローされます。誰かがこれに対する解決策を持っていますか?
XmlReader
で試してみましたが、物事が混乱し、正しく機能しません。 XDocument.Load
はうまく機能しますが、複数のルートを持つファイルがある場合は機能しません。
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
_を呼び出す前に、ノードを1つの仮想ルートの下にラップすることです。お気に入り:
_var fragments = File.ReadAllText("fragment.xml");
var myRootedXml = "<root>" + fragments + "</root>";
var doc = XDocument.Parse(myRootedXml);
_
このアプローチは小さなxmlファイルに限定されています-最初にファイルをメモリに読み込む必要があるためです。大きな文字列を連結するということは、メモリ内の大きなオブジェクトを移動することを意味します。これは避けるのが最善です。
パフォーマンスが重要な場合は、優れた@ Martin-Honnenの回答( https://stackoverflow.com)で説明されているように、ノードをXDocument
を介して1つずつXmlReader
に読み込む必要があります。/a/18203952/2440262 )
XmlReader
が有効なxmlを反復処理することを当然のことと見なし、パフォーマンスが重要であるAPIを使用する場合は、代わりに結合ストリームアプローチを使用できます。
_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-たとえばを参照 https://Gist.github.com/svejdo1/b9165192d313ed0129a679c927379685
注:XDocument
は、xml全体をメモリにロードします。したがって、大きなファイルには使用しないでください。代わりに、反復にXmlReader
を使用し、XNode.ReadFrom(...)
を介してクリスピービットのみをXElement
としてロードします。
フラグメントを処理できる.NETFrameworkのメモリ内ツリー表現は.NETのDOM実装のXmlDocumentFragment
のみであるため、XmlDocument
とフラグメントを作成する必要があります。
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を作成する必要があるという提案に同意します。ただし、ファイルの内容を含む文字列を取得する代わりに、XmlReaderでXNode.ReadFrom
を使用できます。
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 })));
これは、すべてを文字列に読み込むよりも効果的かつ効率的に機能する可能性があります。
XmlDocument.Load()を使用する場合は、コンテンツをルートノードでラップする必要があります。
またはあなたはこのような何かを試すことができます...
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
XmlDocument d = new XmlDocument();
d.CreateElement().InnerText = xmlReader.ReadOuterXml();
}
}
XMLドキュメントに複数のルート要素を含めることはできません。 1つのルート要素が必要です。あなたは一つのことをするかもしれません。すべてのfragment
要素を取得し、それらをルート要素にラップして、XDocument
で解析します。
これは、考えられる最善かつ最も簡単なアプローチです。