2010-09-21 84 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