2010-10-29 33 views
1

我剛剛遇到了一個問題,我的代碼很好地解析了xml,但是一旦我在第二個節點中添加它就開始加載不正確的數據。真正的代碼跨越了一些類和項目,但對於我已經把導致問題的基本原理放在一起我的XML代碼或.NET中是否存在錯誤?

當代碼運行時,我期望輸出是第二個Task節點的內容,而是輸出第一個節點的內容。無論如何檢查設置對象的內部xml是第二個Task節點的時候,它始終從EmailAddresses節點的第一次出現拉動。致電SelectSingleNode("//EmailAddresses")是問題發生的地方。

我解決此問題兩種方式

  1. 獲得任務或設置節點

方案一米的作品在這種情況下,後拆除爲EmailAddresses XPath表達式領先斜線

  • 呼叫Clone()但我相信這會導致我項目中的其他代碼停止工作。

    解決方案2對我來說看起來更像是一種破解,而不是真正的解決方案。

    我的問題是我是否正確地做到了這一點,並且.NET中存在一個錯誤(所有版本),還是我只是把XML拉錯了?

    C#代碼

    var doc = new XmlDocument(); 
    doc.Load(@"D:\temp\Sample.xml"); 
    
    var tasks = doc.SelectSingleNode("Server/Tasks"); 
    
    foreach (XmlNode threadNode in tasks.ChildNodes) 
    { 
        if (threadNode.Name.ToLower() != "thread") 
        { 
         continue; 
        } 
    
        foreach (XmlNode taskNode in threadNode.ChildNodes) 
        { 
         if (taskNode.Name.ToLower() != "task" || taskNode.Attributes["name"].Value != "task 1") 
         { 
          continue; 
         } 
    
         var settings = taskNode.SelectSingleNode("Settings"); 
    
         var emails = settings.SelectSingleNode("//EmailAddresses"); 
    
         Console.WriteLine(emails.InnerText); 
        } 
    } 
    

    的XML

    <?xml version="1.0"?> 
    <Server> 
        <Tasks> 
         <Thread> 
          <Task name="task 2"> 
           <Settings> 
            <EmailAddresses>task 2 data</EmailAddresses> 
           </Settings> 
          </Task> 
         </Thread> 
         <Thread> 
          <Task name="task 1"> 
           <Settings> 
            <EmailAddresses>task 1 data</EmailAddresses> 
           </Settings> 
          </Task> 
         </Thread> 
        </Tasks> 
    </Server> 
    
  • +11

    ,它在.NET中的錯誤是非常小的可能性。 – 2010-10-29 19:04:22

    +0

    我認爲在XPath中,// EmailAddresses將返回一組XMLnodes。您是否嘗試過doc.SelectNodes(「// EmailAddresses」),然後獲取第二個? – dotariel 2010-10-29 19:05:16

    +5

    首先,最後,永遠懷疑自己。 – duffymo 2010-10-29 19:11:01

    回答

    5

    http://www.w3.org/TR/xpath/#path-abbrev

    //是短期的 /descendant-or-self::node()/。對於 例如,//para是短期的 /descendant-or-self::node()/child::para ,因此將在 選擇任何對位元素的文檔(甚至對位元素 是文檔元素將通過//para因爲文檔元素選擇 節點是的一個子根節點);

    並且:

    .的一個地點步驟是用於短 self::node()。特別是 與//一起使用。對於 例如,位置路徑.//para 是短期的

    self::node()/descendant-or-self::node()/child::para 
    

    ,因此將選擇所有的para後代上下文節點的 元件。

    相反的:

    var settings = taskNode.SelectSingleNode("Settings"); 
    
    var emails = settings.SelectSingleNode("//EmailAddresses"); 
    

    用途:

    var emails = taskNode.SelectSingleNode("Settings/EmailAddresses"); 
    
    3

    //XPath expression沒有做什麼,你認爲它。它selects nodes in the document from the current node that match the selection no matter where they are

    換句話說,它不受當前範圍的限制,它實際上是爬行備份文檔樹並從根元素開始匹配。

    要在當前範圍內選擇第一個<EmailAddresses>元素,你只需要:

    var emails = settings.SelectSingleNode("EmailAddresses"); 
    
    相關問題