我有一个 flat 格式的XML文档:
<root>
<node-one>
<parent-id />
<node-id>1</node-id>
<value>foo</value>
</node-one>
<node-two>
<parent-id>1</parent-id>
<node-id>2</node-id>
<value>bar</value>
</node-two>
<node-three>
<parent-id>1</parent-id>
<node-id>3</node-id>
<value>baz</value>
</node-three>
<node-four>
<parent-id>3</parent-id>
<node-id>4</node-id>
<value>qux</value>
</node-four>
</root>
我想将它转换为像这样的分层树状结构:
<root>
<node-one>
<parent-id />
<node-id>1</node-id>
<value>foo</value>
<node-two>
<parent-id>1</parent-id>
<node-id>2</node-id>
<value>bar</value>
</node-two>
<node-three>
<parent-id>1</parent-id>
<node-id>3</node-id>
<value>baz</value>
<node-four>
<parent-id>3</parent-id>
<node-id>4</node-id>
<value>qux</value>
</node-four>
</node-three>
</node-one>
</root>
使用XmlDocument/XDocument
是否有一种优雅的方式来实现它?
任何帮助都会非常感激。
答案 0 :(得分:1)
尝试递归算法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication4
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static List<XElement> nodes;
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
nodes = doc.Root.Elements().ToList();
XElement parent = new XElement("root");
RecursvieAdd(parent, "");
XDocument doc2 = new XDocument(parent);
}
static void RecursvieAdd(XElement parent, string parentId)
{
foreach(XElement child in nodes.Where(x => (string)x.Element("parent-id") == parentId))
{
XElement newChild = new XElement(child);
parent.Add(newChild);
string id = (string)child.Element("node-id");
RecursvieAdd(newChild, id);
}
}
}
}
答案 1 :(得分:0)
您可以使用XPaths或Linq来完成此操作。自从我最近使用XPath以来,我将向您展示如何采用这种方式。
(您可能必须在参考浏览器中添加对System.Xml的一些引用。)
检查此示例代码(包括提示的注释):
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
namespace xmlTest
{
internal class Program
{
public static void Main(string[] args)
{
var document = CreateDocument();
// Gets all children of the root element whose name starts with "node".
var nodeElements = document.XPathSelectElements("/root/*[starts-with(name(), 'node')]").ToList();
// Creates Tuples in the fashion: { 1, $NODE_ONE }, { 2, $NODE_TWO }, ...
// This is done because some values might be skipped.
var indexedNodes = nodeElements.Select(x => new Tuple<int, XElement>(int.Parse(x.Descendants("node-id").First().Value), x)).ToList();
foreach(var indexedNode in indexedNodes)
{
var parentId = GetParentNodeId(indexedNode.Item2);
if (parentId != null)
{
// Remove the node from its parent.
indexedNode.Item2.Remove();
// Add the node to the new parent.
var newParent = indexedNodes.First(x => x.Item1 == parentId).Item2;
newParent.Add(indexedNode.Item2);
}
}
Console.WriteLine(document.ToString());
}
static int? GetParentNodeId(XElement element) {
try {
var parentId = int.Parse(element.Descendants("parent-id").First().Value);
return parentId;
}
catch // Add some appropriate error handling here.
{
return null;
}
}
private static XDocument CreateDocument()
{
const string xml =
"<root> <node-one> <parent-id /> <node-id>1</node-id> <value>foo</value> </node-one> <node-two> <parent-id>1</parent-id> <node-id>2</node-id> <value>bar</value> </node-two> <node-three> <parent-id>1</parent-id> <node-id>3</node-id> <value>baz</value> </node-three> <node-four> <parent-id>3</parent-id> <node-id>4</node-id> <value>qux</value> </node-four> </root>";
return XDocument.Parse(xml);
}
}
}
从输出中可以看出,您对元素所做的所有更改都已反映在XDocument中。这是因为在使用X-classes时,所有更改都已到位。
编辑:您需要更改一些代码才能将其包含在您的应用中,例如: CreateDocument
方法,但这应该很容易:)