在一个XmlTextReader对象读出的“假”的XML文档(XML片段)(Read a '

2019-07-20 10:22发布

[案例]我已经收讫一堆“XML文件”有关大数量的文档它们的元数据。 至少,我是这样要求的。 我收到其中“XML文件”没有根元素,它们的结构是这样的(我留下了一堆元素):

<folder name = "abc"></folder>
<folder name = "abc/def">
<document name = "ghi1">
</document>
<document name = "ghi2">
</document>
</folder>

[问题]当我尝试读取该文件中的XmlTextReader对象失败告诉我,没有根元素。

[电流的解决方法]当然我可以读取该文件作为流,附加<xmlroot>和</ xmlroot>和写入流到一个新的文件,并读出一个在XmlTextReader的。 这正是我现在做的,但我不喜欢“篡改”与原始数据。

[要求的解决方案]据我所知,我应该使用的XmlTextReader这一点,与DocumentFragment的选项。 然而,这给编译时错误:

类型的未处理的异常“System.Xml.XmlException”发生在system.xml.dll的

其他信息:不支持部分内容解析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);
        }
    }
}

Answer 1:

即使XmlReader可以读取的内容使用的数据ConformanceLevel.Fragment这表现在的Martijn选项,似乎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 = "<root>".ToCharArray();
        _rootEnd = "</root>".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(...)将只返回<root>元素。 后续调用读取流为正常,直到达到流的末尾,则结束标记被输出。

该代码是有点......我没意见...主要是因为我想处理一些地方有人试图在同一时间读取数据流少于6个字符永不会-发生的情况。



Answer 2:

这工作:

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


文章来源: Read a 'fake' xml document (xml fragment) in a XmlTextReader object