简体   繁体   中英

Creating XML from the parent node information

I have an xml file that has information of the roots as follows: usequery attribute has a SQL query from which the XML element data is populated from.

<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>

From this I need to generate an XML tree as follows. As of now I already have individual XElements for leve2, level21, level22, level31. But how do I create XML but adding these elements in the XML format as below from the parentid information above?

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

I don't know where the value of attrib1 and attrib2 attributes come from. But as far as the hierarchical structure of the output XML tree is concerned, you could construct it recursively, using something like this:

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);

This solution works independent of order of <root> elements in the input file. selectChildNodes is a delegate that accepts the index of parent node as the input parameter and returns all child nodes of that element recursively. The output would be like this, without attributes:

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

The value of node attributes could be included when constructing each node with new XElement .

You can do it like this:

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);
}

Basically, walk through the elements, and for each find the parent in a dictionary, add it as a child to that parent and finally add it to the dictionary, so that it can be parent itself. This assumes that parent is always declared before all its children.

With your source data, it creates the following result:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM