我有一个没有根的 XML 文件。我无法改变这一点。我正在尝试解析它,但XDocument.Load
不会这样做。我尝试设置ConformanceLevel.Fragment
,但仍然抛出异常。有人对此有解决方案吗?
我试过了XmlReader
,但事情搞砸了,无法正常工作。XDocument.Load
效果很好,但是如果我有一个具有多个根的文件,则不会。
我有一个没有根的 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
. 喜欢:
var fragments = File.ReadAllText("fragment.xml");
var myRootedXml = "<root>" + fragments + "</root>";
var doc = XDocument.Parse(myRootedXml);
这种方法仅限于小型 xml 文件——因为您必须先将文件读入内存;并且连接大字符串意味着在内存中移动大对象-最好避免。
如果性能很重要,您应该按照出色的@Martin-Honnen 的回答(https://stackoverflow.com/a/18203952/2440262)中的说明XDocument
逐个读取节点XmlReader
如果您使用的 API 认为XmlReader
迭代有效 xml 是理所当然的,并且性能很重要,那么您可以使用joined-stream 方法来代替:
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
}
}
多流 - 参见例如https://gist.github.com/svejdo1/b9165192d313ed0129a679c927379685
注意:XDocument
将整个 xml 加载到内存中。所以不要将它用于大文件 - 而是XmlReader
用于迭代并仅加载脆的位XElement
通过XNode.ReadFrom(...)
.NET 框架中唯一可以处理片段的内存树表示是XmlDocumentFragment
.NET 的 DOM 实现,因此您需要创建一个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 作为包装器的建议。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 })));
这可能比将所有内容读入字符串更好、更有效。
如果您想使用 XmlDocument.Load() 那么您需要将内容包装在根节点中。
或者你可以尝试这样的事情......
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
XmlDocument d = new XmlDocument();
d.CreateElement().InnerText = xmlReader.ReadOuterXml();
}
}
XML 文档不能有多个根元素。需要一个根元素。你可以做一件事。获取所有fragment
元素并将它们包装到根元素中并使用XDocument
.
这将是人们能想到的最好和最简单的方法。