Создание XML из информации родительского узла - PullRequest
0 голосов
/ 07 февраля 2012

У меня есть 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 следующим образом. На данный момент у меня уже есть отдельные XElements для leve2, level21, level22, level31. Но как мне создать XML, но добавить эти элементы в формате XML, как показано ниже, из информации о парентиде выше?

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

Ответы [ 2 ]

0 голосов
/ 09 февраля 2012

Вы можете сделать это следующим образом:

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

По сути, пройтись по элементам, и для каждого найти родителя в словаре, добавить его в качестве дочернего для этого родителя и, наконец, добавить его всловарь, так что он может быть родителем сам.Это предполагает, что parent всегда объявляется перед всеми его потомками.

С вашими исходными данными он создает следующий результат:

<result>
  <level1>
    <level2>
      <level21 />
      <level22 />
    </level2>
    <level3>
      <level31 />
    </level3>
  </level1>
</result>
0 голосов
/ 09 февраля 2012

Я не знаю, откуда берутся значения атрибутов attrib1 и attrib2. Но что касается иерархической структуры выходного 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.

...