【问题标题】:Recursive search for element part of XmlSchemaDocument递归搜索 XmlSchemaDocument 的元素部分
【发布时间】:2017-05-06 22:17:28
【问题描述】:

在下面的代码中,我正在 XmlSchemaDocument 中搜索一个元素。如果元素是 XmlSchemaDocument 的一部分,则迭代工作得很好。

 public void FindSchemaElement(string elementName, string dataType, List<XmlSchemaElement> allChildren, string parentName)
    {
        try
        {
            List<XmlSchemaElement> temp = new List<XmlSchemaElement>();
            temp.AddRange(allChildren);
            foreach (XmlSchemaElement e in allChildren)
            {
                if (e.Name != elementName && e.RefName.Name != elementName &&
                    (dataType == "" || e.SchemaTypeName.Name != dataType)) continue;
                if (e.Parent == null || e.Parent is XmlSchema)
                {
                    ElementToBeFound = e;
                    return;
                }
                var parent = e.Parent;
                while (parent != null && parent.GetType() != typeof(XmlSchemaElement))
                    parent = parent.Parent;

                if (parent != null && ((XmlSchemaElement) parent).Name == parentName)
                {
                    ElementToBeFound = e;
                    return;
                }
                if (parent == null || parent.GetType() == typeof(XmlSchema)) ElementToBeFound = e;
            }
            if (ElementToBeFound != null) return;
            _childrenList.Clear();
            if (temp.Count > 0)
                GetNextChildren(temp, dataType, elementName, parentName);
        }
        catch(Exception exception){Debug.WriteLine("FindSchemaElement: "+exception.Message);}
    }

得到孩子:

private void GetNextChildren(List<XmlSchemaElement> allChildren, string dataType, string elementName, string parentName = "")
        {
            try
            {
                foreach (XmlSchemaElement e in allChildren)
                    GetChildren(e);
                if (parentName != string.Empty)
                    FindSchemaElement(elementName, dataType, _childrenList, parentName);
                else
                    FindSubsGroups(elementName, dataType, _childrenList);
            }
            catch (Exception ex)
            { Debug.WriteLine("GetNextChildren: " + ex.Message); }
        }

在 GetChildren() 中 - 我只是检查元素的类型(序列、选择元素),如果它是一个元素,我会将其添加到 _childrenList。

但是,如果找不到该元素,我会陷入循环,最终内存不足(我使用的 .xsd 文件非常大)。 我注意到只有在 .xsd 中存在循环时才会出现此问题 - 如图所示: 有没有办法在没有找到元素但是有这样一个循环的时候停止迭代?

【问题讨论】:

  • 循环中有break关键字用于停止迭代。
  • 我知道.. 但是我怎么知道什么时候需要停止循环呢?我需要确保所有元素都已检查,然后我可以停止循环。
  • 函数GetChildrenFindSubsGroups有什么作用?你也可以发一下吗?
  • 在 GetChildren() 中 - 我只是检查元素的类型(序列、选择元素),如果它是一个元素,我会将其添加到 _childrenList。
  • 对于子组,我只是获取同一子组的元素。

标签: c# loops xsd out-of-memory xmldocument


【解决方案1】:

您需要跟踪您已经搜索过的内容。 然后 GetNextChildren 可以检查它是否已经处理了该元素,它可以忽略它。从你的主函数调用它应该传入一个新的 HashSet

GetNextChildren(new HashSet<XmlSchemaElement>(), ....);

你的代码有点乱,所以我刚刚做了一些防止无限递归的工作。

   private void GetNextChildren(HashSet<XmlSchemaElement> searchedElements, List<XmlSchemaElement> allChildren, string dataType, string elementName, string parentName = "")
    {
        try
        {
            foreach (XmlSchemaElement e in allChildren)
            {
                if (searchedElements.Contains(e) == false)
                {
                    searchedElements.Add(e);

                   // Search for it
                   // GetNextChildren(searchedElements, ....);
                }
            }
        }
        catch (Exception ex)
        { Debug.WriteLine("GetNextChildren: " + ex.Message); }
    }

您还应该注意,模式也可以在循环中相互包含(a.xsd 包含 b.xsd,b.xsd 包含 a.xsd)。我认为元素组也是如此。

【讨论】:

  • 工作就像一个魅力。感谢您抽出宝贵的时间。我用你的想法有点不同。我创建了一个外部 HashSet 来存储项目。一旦我检查了一个项目,我就将它添加到 searchedElements 列表中。将新子项添加到列表时,我会根据 searchedElements 列表检查它。如果有人有兴趣,我可以发布更新。
猜你喜欢
  • 2022-08-10
  • 2013-06-26
  • 2020-03-07
  • 1970-01-01
  • 2021-05-10
  • 2016-11-13
  • 1970-01-01
  • 2010-11-07
  • 1970-01-01
相关资源
最近更新 更多