2013-02-23 63 views
2

[案例] 我已經用元數據瞭解了一大堆'xml文件',其中包含大量文檔。至少,這是我所要求的。我收到其中「XML文件」沒有根元素,它們的結構是這樣的(我留下了一堆元素):在XmlTextReader對象中讀取'假'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選項。然而,這給編譯時錯誤:

An unhandled exception of type 'System.Xml.XmlException' occurred in System.Xml.dll

Additional information: XmlNodeType DocumentFragment is not supported for partial content parsing. Line 1, position 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); 
     } 
    } 
} 
+1

您正在使用過時的方法...自.NET 4以來XmlDataDocuments已過時 – 2013-02-23 08:43:06

+0

現在使用XmlTextReader類更改了問題。 – 2013-02-23 10:05:42

+1

實際上自.NET 2.0以來,XmlTextReader已被棄用。改爲使用XmlReader.Create。 – 2013-02-23 10:50:14

回答

2

即使XmlReader可以進行使用來讀取數據Martijn展示的ConformanceLevel.Fragment選項,似乎XmlDataDocument不喜歡有mult iple根元素。

我想我會嘗試一種不同的方法,就像您正在使用的方法,但沒有中間文件。大多數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>元素。隨後的調用將正常讀取流,直到流結束,然後輸出結束標記。

代碼有點...... meh ...主要是因爲我想處理一些從未發生過的情況,即有人試圖一次讀取小於6個字符的流。

3

這工作:

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