2010-09-21 81 views
2

我有一個很大(〜40mb)的XML數據集合,在許多文件中沒有很好地形成,因此我合併它們,添加一個根節點並加載所有xml在XmlDocument 。它基本上是3種不同類型的列表,可以用幾種不同的方式嵌套。本實施例中應顯示大多數情況下:單線程應用程序顯示競爭狀態,如行爲

<Root> 
    <A> 
    <A> 
     <A></A> 
     <A></A> 
    </A> 
    </A> 
    <A /> 
    <B> 
    <A> 
     <A> 
     <A></A> 
     <A></A> 
     </A> 
    </A> 
    </B> 
    <C /> 
</Root> 

林通過使用上一個XmlDocument//A//B//C),所得到的節點集轉換爲數據表,並顯示一個XPath表達式中分離所有A,B和C的節點Datagridview中每個節點類型的所有節點的列表。這工作正常。

但現在我面臨一個更大的文件,只要我加載它,它只顯示我4行。然後我在實際的XmlDocument.SelectNodes發生的行添加了一個斷點,並檢查了結果NodeSet。它向我展示了大約25,000個條目。在繼續加載程序並且哎呦,我所有的25k行都顯示出來了。我試了一遍,我可以重現它。如果我手動跨越XmlDocument.SelectNodes,它就可以工作。如果我不打破那裏,它不會。我不會在我的應用程序中產生單個線程。

如何進一步調試?要找什麼?我已經經歷了多線程庫如jsch(ssh)的這種行爲,但我不明白爲什麼這應該發生在我的情況。

非常感謝!

// class XmlToDataTable: 
private DataTable CreateTable(NamedXPath logType, 
           List<XmlColumn> columns, 
           ITableCreator tableCreator) 
{ 
    // I have to break here --> 
    XmlNodeList xmlNodeList = logFile.GetEntries(logType); 
    // <-- I have to break here 

    DataTable dataTable = tableCreator.CreateTableLayout(columns); 
    foreach (XmlNode xmlNode in xmlNodeList) 
    { 
     DataRow row = dataTable.NewRow(); 
     tableCreator.PopulateRow(xmlNode, row, columns); 
     dataTable.Rows.Add(row); 
    } 
    return dataTable; 
} 

// class Logfile: 
public XmlNodeList GetEntries(NamedXPath e) 
{ 
    return (_xmlDocument != null && _xmlDocument.HasChildNodes) 
         ? _xmlDocument.SelectNodes(e.XPath) 
         : new XmlNullObjectNodeList(); 
} 
// _xmlDocument gets loaded here after reading all xml fragments into a string 
// (ugly, i know. the // ugly! comment reminds me about that ;)) 
private void CreateXmlDoc() 
{ 
    _xmlDocument = new XmlDocument(); 
    _xmlDocument.LoadXml(OPEN_ROOT_ELEMENT + _xmlString + 
          CLOSE_ROOT_ELEMENT); 
    if (DataChanged != null) 
     DataChanged(this, new EventArgs()); 
} 

// class NamedXPath: 
public abstract class NamedXPath 
{ 
    private readonly String _name; 
    private readonly String _xPath; 
    protected NamedXPath(string name, string xPath) 
    { 
     _name = name; 
     _xPath = xPath; 
    } 

    public string Name 
    { 
     get { return _name; } 
    } 

    public string XPath 
    { 
     get { return _xPath; } 
    } 
} 
+0

你可以發佈如何加載_xmlDocument?關於CreateTable的前言 – 2010-09-21 08:26:32

+0

@Henk Holterman編輯我的文章。我讀取字符串中的所有XML,添加並調用XmlDocument.LoadXml(String s)。我知道這很慢,吃了記憶,一旦它起作用,它就會被分析和調整。 – atamanroman 2010-09-21 08:37:18

+0

乍一看,你有一個很奇怪的問題。但是還有什麼可能是相關的?空接收{}塊?背景工作者? – 2010-09-21 08:47:23

回答

0

好的,解決了。 tableCreator是我的戰略模式的一部分,它影響了表格的構建方式。在某實施我做這樣的事情:

XmlNode xn = xmlDocument.SelectSingleNode(fancyXPath); 
// if a node has ancestors, then its a linked list: 
// <a><a><a></a></a></a> 
if(xn.SelectSingleNode("a") != null) 
    xn.SelectSingleNode("a").InnerText = "<IDs of linked list items CSV like here>"; 

這意味着一些文本XML鏈表的即時更換零件而失去嵌套的項目出現。 如果此更改不會影響原始XmlDocument,找到此錯誤不會有問題。即使如此,調試它不應該太難。是什麼讓我的程序的行爲不同,或者根據我是否打不破似乎是以下幾點:

返回值: 第一的XmlNode是 如果沒有 匹配節點發現XPath查詢或空相匹配。不應期望XmlNode 將 連接到XML文檔。即, XML 文檔中出現的更改可能不會出現在 XmlNode中,反之亦然。 (API XmlNode.SelectNodes的說明())

如果我打破那裏,更改寫回原來的XmlDocument,如果我不打破,它不是寫回。不能真正向我自己解釋,但沒有改變XmlNode一切正常。

編輯: 現在我很確定:我的手錶中有XmlNodeList.Count。這意味着,每次我調試,VS叫物業Count,這不僅會返回一個數字,但稱ReadUntil(INT),它刷新內部列表:

internal int ReadUntil(int index) 
{ 
    int count = this.list.Count; 
    while (!this.done && (count <= index)) 
    { 
     if (this.nodeIterator.MoveNext()) 
     { 
      XmlNode item = this.GetNode(this.nodeIterator.Current); 
      if (item != null) 
      { 
       this.list.Add(item); 
       count++; 
      } 
     } 
     else 
     { 
      this.done = true; 
      return count; 
     } 
    } 
    return count; 
} 

這可能引起的怪異行爲。

+0

可能發生的事情是'SelectNodes'中的某種惰性評估。如果您打開調試器並檢查'xmlNodeList',調試器會評估查詢並建立節點列表,並且當您繼續時,修改XML文檔的事實不會影響列表,因爲它已經建成。如果懶惰的評估正在進行,並且列表不是在執行SelectNodes時執行的,而是在枚舉時對該文檔進行更改將更改列表。雖然這是一個瘋狂的猜測。 – 2010-09-22 17:14:21

1

而是先在代碼中直接使用XPath的,我會用一個工具,如sketchPath讓我XPath的權利。您可以加載原始XML或使用原始XML的子集。

使用XPath和您的XML播放,以查看在您的代碼中使用xpath之前是否已選擇預期的節點。

+0

這裏沒有花哨的xpath表達式,// A選擇文檔中所有類型爲A的節點。我知道這是正確的,我用xpath可視化器再次檢查了兩遍。另外,如果我在正確的位置休息,它就可以工作。 – atamanroman 2010-09-21 08:31:32