【问题标题】:Creating XML from the parent node information从父节点信息创建 XML
【发布时间】:2012-02-07 15:32:54
【问题描述】:

我有一个包含根信息的 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 树,如下所示。到目前为止,我已经为 leve2、level21、level22、level31 提供了单独的 XElement。但是,如何创建 XML,但要从上面的 parentid 信息中以 XML 格式添加这些元素,如下所示?

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

【问题讨论】:

  • 第一个样本和第二个样本都不是格式良好的 XML(甚至不是很接近),所以请先向我们展示格式良好的 XML 输入和输出,然后我们可以帮助构建结果的代码.
  • 抱歉,我不得不删除客户提供的一些敏感信息。请立即查看。
  • &lt;elementa&gt; 是从哪里来的?关卡元素的属性呢?此外,第一个文件仍然不是有效的 XML。你不能有像&lt;root="level31" /&gt; 这样的东西。
  • 级别属性来自用户查询中列出的 SQL 查询。当节点信息作为 parentid 给出时,我只需要找到一种构建 XML 文件的方法。就像在 XML 中构建树结构一样。

标签: c# xml linq-to-xml


【解决方案1】:

你可以这样做:

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>

【讨论】:

    【解决方案2】:

    不知道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);
    

    此解决方案独立于输入文件中&lt;root&gt; 元素的顺序。 selectChildNodes 是一个委托,它接受父节点的索引作为输入参数,并递归返回该元素的所有子节点。输出将是这样的,没有属性:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多