在XmlTextReader对象中读取’假’xml文档(xml片段)

[案例]我已经发现了一堆’xml文件’,其中包含有关其中大量文档的元数据。 至少,这就是我的要求。 我收到的’没有根元素的’xml文件’,它们的结构是这样的(我遗漏了一堆元素):

       

[问题]当我尝试读取XmlTextReader对象中的文件时,它无法告诉我没有根元素。

[当前解决方法]当然我可以将文件作为流读取,附加和并将流写入新文件并在XmlTextReader中读取该文件。 这正是我现在正在做的事情,但我不想“篡改”原始数据。

[请求的解决方案]我明白我应该使用XmlTextReader,使用DocumentFragment选项。 但是,这会产生编译时错误:

System.Xml.dll中发生了未处理的“System.Xml.XmlException”类型exception

附加信息:部分内容解析不支持XmlNodeType DocumentFragment。 第1行,第1位。

[错误代码]

 using System.Diagnostics; using System.Xml; namespace XmlExample { class Program { static void Main(string[] args) { string file = @"C:\test.txt"; XmlTextReader tr = new XmlTextReader(file, XmlNodeType.DocumentFragment, null); while(tr.Read()) Debug.WriteLine("NodeType: {0} NodeName: {1}", tr.NodeType, tr.Name); } } } 

尽管可以使用Martijn演示的ConformanceLevel.Fragment选项使XmlReader读取数据,但似乎XmlDataDocument不喜欢具有多个根元素的想法。

我以为我会尝试一种不同的方法,就像你当前使用的方法一样,但没有中间文件。 大多数XML库(XmlDocument,XDocument,XmlDataDocument)都可以将TextReader作为输入,因此我实现了自己的一个。 它的使用方式如下:

 var dataDocument = new XmlDataDocument(); dataDocument.Load(new FakeRootStreamReader(File.OpenRead("test.xml"))); 

实际类的代码:

 public class FakeRootStreamReader : TextReader { private static readonly char[] _rootStart; private static readonly char[] _rootEnd; private readonly TextReader _innerReader; private int _charsRead; private bool _eof; static FakeRootStreamReader() { _rootStart = "".ToCharArray(); _rootEnd = "".ToCharArray(); } public FakeRootStreamReader(Stream stream) { _innerReader = new StreamReader(stream); } public FakeRootStreamReader(TextReader innerReader) { _innerReader = innerReader; } public override int Read(char[] buffer, int index, int count) { if (!_eof && _charsRead < _rootStart.Length) { // Prepend root element return ReadFake(_rootStart, buffer, index, count); } if (!_eof) { // Normal reading operation int charsRead = _innerReader.Read(buffer, index, count); if (charsRead > 0) return charsRead; // We've reached the end of the Stream _eof = true; _charsRead = 0; } // Append root element end tag at the end of the Stream return ReadFake(_rootEnd, buffer, index, count); } private int ReadFake(char[] source, char[] buffer, int offset, int count) { int length = Math.Min(source.Length - _charsRead, count); Array.Copy(source, _charsRead, buffer, offset, length); _charsRead += length; return length; } } 

第一次调用Read(...)将只返回元素。 后续调用正常读取流,直到到达流的末尾,然后输出结束标记。

代码有点…… meh …主要是因为我想处理一些永远不会发生的情况,有人试图一次读取少于6个字符的流。

这有效:

 using System.Diagnostics; using System.Xml; namespace XmlExample { class Program { static void Main(string[] args) { string file = @"C:\test.txt"; XmlReaderSettings settings = new XmlReaderSettings(); settings.ConformanceLevel = ConformanceLevel.Fragment; using (XmlReader reader = XmlReader.Create(file, settings)) { while (reader.Read()) Debug.WriteLine("NodeType: {0} NodeName: {1}", reader.NodeType, reader.Name); } } } }