3

[ケース] 大量のドキュメントに関するメタデータを含む「xml ファイル」を大量に受け取りました。少なくとも、それは私が要求したものでした。ルート要素のない「xmlファイル」で受け取ったものは、次のような構造になっています(要素の束を省略しました):

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

[問題] XmlTextReader オブジェクトでファイルを読み込もうとすると、ルート要素がないと言って失敗します。

[現在の回避策] もちろん、ファイルをストリームとして読み取り、< xmlroot> と < /xmlroot> を追加してストリームを新しいファイルに書き込み、そのファイルを XmlTextReader で読み取ることができます。これはまさに私が今やっていることですが、元のデータを「改ざん」したくないのです。

[要求された解決策] DocumentFragment オプションを指定して XmlTextReader を使用する必要があることを理解しています。ただし、これによりコンパイル時エラーが発生します。

System.Xml.dll で 'System.Xml.XmlException' 型の未処理の例外が発生しました

追加情報: 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);
        }
    }
}
4

2 に答える 2

4

これは機能します:

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);
            }
        }
    }
}
于 2013-02-23T13:00:19.973 に答える
2

Martijn によって示されているようにXmlReader、オプションを使用してデータを読み取るようにすることはできますが、複数のルート要素を持つという考えが気に入らないようです。ConformanceLevel.FragmentXmlDataDocument

現在使用しているものと同じように、中間ファイルを使用せずに、別のアプローチを試してみようと思いました。ほとんどの 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文字未満のストリームを読み取ろうとする、決して起こらないケースを処理したかったためです。

于 2013-02-23T15:49:10.483 に答える