2015-03-13 147 views
2

我真的很喜歡Json.NET中的JsonReader,因爲您始終知道當前位置的路徑JsonReader。例如,我們有這樣的JSON:獲取當前XmlReader位置的'路徑'

{ 
    "name" : 
    { 
     "first": "John", 
     "last": "Smith" 
    } 
} 

如果我們站在或「約翰」的元素,JsonReader.Path將是「name.first」

有沒有辦法實現與XmlReader類似的東西?也許使用XPath?例如,我們有這樣一個xml:

<root> 
    <name> 
     <first>John/<first> 
     <last>Smith</last> 
    </name> 
</root> 

我想「/根/名/第一」,而站在「約翰」和「/根/姓/」而站在「史密斯」

+1

這並不回答你的問題,但如果你的XML不是很可笑,你總是可以使用'XDocument',它允許你對你的XML執行linq查詢,所以你不會被只讀的讀取困住。 – JNYRanger 2015-03-13 13:08:32

+0

@JNYRanger我在想這件事,但是我的文件可能很大,所以在這裏沒有運氣。無論如何,謝謝你的提示 – 2015-03-13 13:42:15

回答

-1

我使用XmlDocumentXmlNode類來處理XML數據。 雖然站在節點上,但在這種情況下,您的XmlNode在這種情況下是x。沒有這樣的方法來獲得節點的路徑。但是這個代碼做到了。

 XmlDocument doc = new XmlDocument(); 
     doc.LoadXml("<root>" + 
         "<name>" + 
          "<first>John</first>" + 
          "<last>Smith</last>" + 
         "</name>" + 
        "</root>"); 

     XmlNodeList liste = doc.FirstChild.SelectNodes("*/first"); 
     XmlNode x = liste[0]; //Some Node 
     string path = ""; 
     while (!x.Name.Equals("document")) 
     { 
      path = x.Name + "\\" + path; 
      x = x.ParentNode; 
     } 
+0

這個問題明確引用了'XmlReader'。爲什麼?誰知道,但是你的解決方案將會崩潰並且燒錄更大的文件。 – Gusdor 2016-04-09 18:49:12

1

似乎有沒有辦法使用標準的.NET功能來做到這一點,所以我想出了我自己的類。

internal sealed class XmlReaderWrapperWithPath : IDisposable 
{ 
    private const string DefaultPathSeparator = "."; 

    private readonly Stack<string> _previousNames = new Stack<string>(); 
    private readonly XmlReader _reader; 
    private readonly bool _ownsReader; 

    public XmlReaderWrapperWithPath(XmlReader reader, bool ownsReader) 
    { 
     if (reader == null) 
     { 
      throw new ArgumentNullException("reader"); 
     } 

     _ownsReader = ownsReader; 
     _reader = reader; 
     PathSeparator = DefaultPathSeparator; 
    } 

    public bool Read() 
    { 
     var lastDepth = Depth; 
     var lastName = Name; 

     if (!_reader.Read()) 
     { 
      return false; 
     } 

     if (Depth > lastDepth) 
     { 
      _previousNames.Push(lastName); 
     } 
     else if (Depth < lastDepth) 
     { 
      _previousNames.Pop(); 
     } 

     return true; 
    } 

    public string Name 
    { 
     get 
     { 
      return _reader.Name; 
     } 
    } 

    public string Value 
    { 
     get 
     { 
      return _reader.Value; 
     } 
    } 

    private int Depth 
    { 
     get 
     { 
      return _reader.Depth; 
     } 
    } 

    public string Path 
    { 
     get 
     { 
      return string.Join(PathSeparator, _previousNames.Reverse()); 
     } 
    } 

    public string PathSeparator { get; set; } 

    #region IDisposable 

    public void Dispose() 
    { 
     if (_ownsReader) 
     { 
      _reader.Dispose(); 
     } 
    } 

    #endregion 
} 

請注意,該類不構成XPath(因此沒有屬性的路徑),但這足以滿足我的需要。希望這可以幫助某人。