从父节点信息创建XML

本文关键字:XML 创建 信息 父节点 | 更新日期: 2023-09-27 18:22:48

我有一个xml文件,其中包含如下根的信息:usequery属性有一个SQL查询,从中填充XML元素数据。

<ARAXmlFormat>
    <root name="level1" index = "1" parentid ="0" haschildren="yes"/>
    <root name="level2" index = "2" parentid ="1" haschildren="yes" usequery="query2"/>
    <root name="level21" index = "3" parentid ="2" haschildren="no" usequery="query1"/>
    <root name="level22" index = "4" parentid ="2" haschildren="no" usequery="query3"/>
    <root name="level3" index = "5" parentid ="1" haschildren="yes"/>
    <root name="level31" index = "6" parentid ="5" haschildren="no" usequery="query4"/>
</ARAXmlFormat>

由此,我需要生成一个XML树,如下所示。到目前为止,我已经有了级别2、级别21、级别22和级别31的单独XElement。但是,我如何创建XML,但按照下面的XML格式从上面的parentid信息中添加这些元素呢?

<level1>
  <level2>
      <level21 attrib1 ="val1" attrib2="val2"/>
      <level22 attrib1 ="val1" attrib2="val2"/>
  </level2>
  <level3>
       <level31 attrib1 ="val1" attrib2="val2"/>
  </level3>
</level1>

从父节点信息创建XML

你可以这样做:

var source = XDocument.Parse(xml); // or whatever
var sourceElems = source.Root.Elements("root");
var result = new XDocument(new XElement("result"));
var resultElems = new Dictionary<int, XElement>();
resultElems.Add(0, result.Root);
foreach (var sourceElem in sourceElems)
{
    var resultElem = new XElement((string)sourceElem.Attribute("name"));
    int parentId = (int)sourceElem.Attribute("parentid");
    resultElems[parentId].Add(resultElem);
    resultElems.Add((int)sourceElem.Attribute("index"), resultElem);
}

基本上,遍历元素,在字典中找到每个元素的父元素,将其作为子元素添加到该父元素,最后将其添加到字典中,这样它就可以成为父元素本身。这假设父级总是在其所有子级之前声明。

使用源数据,它会创建以下结果:

<result>
  <level1>
    <level2>
      <level21 />
      <level22 />
    </level2>
    <level3>
      <level31 />
    </level3>
  </level1>
</result>

我不知道attrib1attrib2属性的值从哪里来。但是,就输出XML树的层次结构而言,您可以递归地构建它,使用以下方法:

var doc = XDocument.Load("roots.xml"); // read input xml file
Func<int, IEnumerable<XElement>> selectChildNodes = null; // declare delegate
selectChildNodes = parentId => doc.Elements("ARAXmlFormat").Elements().Where(
                        p => p.Attribute("parentid").Value == parentId.ToString()
                ).Select(
                   x => new XElement(
                                        x.Attribute("name").Value,
                                        selectChildNodes(Convert.ToInt32(x.Attribute("index").Value))
                                     )
                );
IEnumerable<XElement> levels = selectChildNodes(0);

此解决方案的工作方式与输入文件中<root>元素的顺序无关。selectChildNodes是一个委托,它接受父节点的索引作为输入参数,并递归地返回该元素的所有子节点。输出是这样的,没有属性:

<level1>
  <level2>
    <level21 />
    <level22 />
  </level2>
  <level3>
    <level31 />
  </level3>
</level1>

当用new XElement构造每个节点时,可以包含节点属性的值。