如何递归地从XML树中读取相同的子元素类型?

时间:2014-01-10 01:06:34

标签: c# .net xml linq

我有以下格式的示例xml文件: -

enter image description here 另外,我有一个如下所示的Control类:

 class Control 
 {
    private string id;
    public string Id
    {
      get { return id; }
      set { id = value; }
    }


    private string controlType;
    public string ControlType
    {
      get { return controlType; }
      set { controlType = value; }
    }

    private string searchProperties;
    public string SearchProperties
    {
      get { return searchProperties; }
      set { searchProperties = value; }
    }

    public List<Control> ChildrenControl = new List<Control>();
  }

我需要阅读上面提到的XML文件并填充代码。我不知道如何递归地做到这一点。我正在考虑将Linq用于XML,但不确定如何在这种情况下递归使用它,其中父元素和子元素的类型相同。有人可以帮我解决这个问题吗?

谢谢, Harit

2 个答案:

答案 0 :(得分:0)

<强>更新

尝试以下方法。它使用Linq to XML和递归函数来解析XML文档中的控件。它假定您的XML数据存在于名为“Controls.xml”的文件中,显然是您的Control类。它不是最好的代码,但它应该让你开始。

private void ParseControlsData()
{
    var doc = XDocument.Load("Controls.xml");

    var controls = from control in doc.Element("controls").Elements("control")
                   select CreateFromXElement(control);

    var controlsList = controls.ToList();

    Console.ReadLine();
}

private Control CreateFromXElement(XElement element)
{
    var control = new Control()
    {
        Id = (string)element.Attribute("id"),
        ControlType = (string)element.Attribute("controlType"),
        SearchProperties = (string)element.Attribute("searchProperties")
    };

    var childrenElements = element.Element("childControls");
    if (childrenElements != null)
    {
        var children = from child in childrenElements.Elements("control")
                       select CreateFromXElement(child);

        control.ChildrenControl = children.ToList();
    }

    return control;
}

注意:

  • 在ParseControlsData函数中,它使用查询表达式语法选择文档中名为“controls”(您的根)的第一个元素,然后选择名为“control”的所有子元素。 CreateFromXElement函数内部发生了一个非常相似的表达式,除了它需要找到一个名为“childControls”的元素。
  • 没有真正的错误检查。你肯定需要一些。

<强>更新

不要这样做,它对你的例子不起作用,因为你有值存储在属性中,默认情况下,DataContractSerializer + DataContractAttributes组合不支持它(没有一大堆额外的工作)。其他选项是Linq to XML(如您所建议的)和使用XmlSerializer(类似于DataContractSerializer,但使用自己的一组属性)。我会进一步研究它。

上一个答案:

将XML文档转换为对象图的一种方法是使用DataContract属性标记要创建的类,并使用DataContractSerializer。您需要做的就是确保DataContract(Name =“X”)和DataMember(Name =“Y”)匹配XML中元素的名称。

查看我在XML Element Selection上的答案,该答案正在执行您想要的操作(使用现有XML并将其转换为对象图)。您可能不必担心该用户遇到的CDATA内容,因此您的解决方案可能会更简单一些。

另外,请查看我在How to catch/send XML doc with various sub arrays?上的答案,该答案正在执行相反的操作(用户希望从对象图创建XML)。

如果你不知道,我是DataContractSerializer的粉丝:)

答案 1 :(得分:0)

您可以使用Func<>委托来使用递归,但必须在指定实际委托逻辑之前声明它:

var xDoc = XDocument.Load("Input.xml");

Func<XElement, List<Control>> childControlsQuery = null;
childControlsQuery =
    x => (from c in x.Elements("control")
          select new Control
          {
              Id = (string)c.Attribute("id"),
              ControlType = (string)c.Attribute("controltype"),
              SearchProperties = (string)c.Attribute("searchproperties"),
              ChildrenControl = childControlsQuery(c.Element("childControls") ?? new XElement("childControls"))
          }).ToList();

var controls = childControlsQuery(xDoc.Root);

如果您确定始终有?? new XElement("childControls")元素,即使给定控件没有任何子元素,也可以删除childControls

如果你确定总有一个主控制,你可以得到它:

var mainControl = controls.First();