[英]Transforming flat XML to a hierarchy (XML or Object) with C# and LINQ
我看到有关同一主题的几篇文章,但是一些因素的组合使这个问题更具挑战性。
我需要转换如下所示的平面XML:
string myXML = "<a>" +
"<b><levelNumber>01</levelNumber><name>top1</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2a</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2b</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3a</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3b</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3c</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2c</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3d</name></b>" +
"<b><levelNumber>01</levelNumber><name>top2</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2d</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2e</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2f</name></b>" +
"</a>";
...或者嵌套对象结构,甚至只是分层XML结构,最好使用LINQ。 决定层次结构的值是levelNumber元素。 只是那些具有较高编号的元素应该是前面较低编号的子元素。
所需的XML应该如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<a>
<b>
<levelNumber>01</levelNumber>
<name>top1</name>
</b>
<children>
<b>
<levelNumber>05</levelNumber>
<name>lev2a</name>
</b>
<b>
<levelNumber>05</levelNumber>
<name>lev2b</name>
</b>
<children>
<b>
<levelNumber>10</levelNumber>
<name>lev3a</name>
</b>
<b>
<levelNumber>10</levelNumber>
<name>lev3b</name>
</b>
<b>
<levelNumber>10</levelNumber>
<name>lev3c</name>
</b>
</children>
<b>
<levelNumber>05</levelNumber>
<name>lev2c</name>
</b>
<children>
<b>
<levelNumber>10</levelNumber>
<name>lev3d</name>
</b>
</children>
</children>
<b>
<levelNumber>01</levelNumber>
<name>top2</name>
</b>
<children>
<b>
<levelNumber>05</levelNumber>
<name>lev2d</name>
</b>
<b>
<levelNumber>05</levelNumber>
<name>lev2e</name>
</b>
<b>
<levelNumber>05</levelNumber>
<name>lev2f</name>
</b>
</children>
</a>
尽管有一些相关的解决方案,但让我感到困扰的部分是需要嵌套相同类型的元素。
我先从偷看平面结构的方法开始:(使用函数提取级别的数值)
int firstSibling = GetLevel(element.ElementsAfterSelf("b").First());
var childElements = element.ElementsAfterSelf("b")
.TakeWhile(x => GetLevel(x) < firstSibling); // all elements with higher level number
然后,我将通过childElements(例如具有子元素的lev2b元素)进行递归,但结果是存在更多的5级,而且我不确定如何使用循环或LINQ或两者来捕获它们。
另外,如果您希望处理无限深度,则必须递归处理该子元素的函数,并通过相同的过程在每个子元素中搜索子元素。
就像我在开始时所说的那样,整个结构最终将成为嵌套的对象结构,但是如果这太困难了,我愿意使用嵌套的XML结构。
任何对此的想法都将受到欢迎。
谢谢。 Corneel。
我们能够提出一种使用LINQ并提供所需的分层XML的解决方案。
void Main()
{
var elements = GetElements(GetMyXml());
//elements.Dump();
var workingStorageVariables = GetWorkingStorageVariables(elements);
//workingStorageVariables.Dump();
var tree = new XElement("a",
workingStorageVariables
.Where(h => h.Level == 1)
.Select
(
h => new XElement("children",
new XElement("b",
new XElement("levelNumber", h.LevelText),
new XElement("name", h.VariableName),
GetChildVariables(workingStorageVariables, h))
)
)
);
Console.WriteLine(tree);
}
public static string GetMyXml()
{
return "<a>" +
"<b><levelNumber>01</levelNumber><name>top1</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2a</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2b</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3a</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3b</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3c</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2c</name></b>" +
"<b><levelNumber>10</levelNumber><name>lev3d</name></b>" +
"<b><levelNumber>01</levelNumber><name>top2</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2d</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2e</name></b>" +
"<b><levelNumber>05</levelNumber><name>lev2f</name></b>" +
"</a>";
}
public static IEnumerable<MyElement> GetElements(string xml)
{
XDocument doc = XDocument.Parse(xml);
return doc.Root
.Elements()
.Elements()
.Select(x => new MyElement
{
ElementName = x.Name.LocalName,
ElementValue = x.Value
});
}
public static IEnumerable<WorkingStorageVariable> GetWorkingStorageVariables(IEnumerable<MyElement> elements)
{
List<WorkingStorageVariable> workingStorageVariables = new List<WorkingStorageVariable>();
int level = 0;
string levelText = String.Empty;
string variableName = String.Empty;
foreach (var element in elements)
{
if (element.ElementName == "levelNumber")
{
levelText = element.ElementValue;
level = Convert.ToInt32(element.ElementValue);
}
if (level != 0 && element.ElementName == "name")
{
variableName = element.ElementValue;
workingStorageVariables.Add(new WorkingStorageVariable { Level = level, LevelText = levelText, VariableName = variableName });
level = 0;
}
}
return workingStorageVariables;
}
public static IEnumerable<XElement> GetChildVariables(
IEnumerable<WorkingStorageVariable> workingStorageVariables,
WorkingStorageVariable parent)
{
return
workingStorageVariables
.SkipWhile(h => h != parent)
.Skip(1)
.TakeWhile(h => h.Level > parent.Level)
.Select(h =>
new XElement("children",
new XElement("b",
new XElement("levelNumber", h.LevelText),
new XElement("Name", h.VariableName),
GetChildVariables(workingStorageVariables, h)
))
);
}
public class MyElement
{
public string ElementName { get; set; }
public string ElementValue { get; set; }
}
public class WorkingStorageVariable
{
public int Level { get; set; }
public string LevelText { get; set; }
public string VariableName { get; set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.