如何使用c#代码LINQ将多层XML展平为单层XML
本文关键字:XML 单层 何使用 代码 LINQ | 更新日期: 2023-09-27 17:58:57
我读了一些关于扁平化XML结构的文章,这样每个元素及其值都会变成根元素上的属性。然而,我的要求是按照下面的示例来压平输入XML,对此我找不到任何帮助。
我有一个XML结构,如下所示,
<RATES ID="1" RatesEffectivateDate="27/02/2014">
<Type Name="Type1" Code="A">
<Del ID="D1">
<Field1>10</Field1>
<Field2>20</Field2>
<Field3>30</Field3>
<Field4>40</Field4>
</Del>
<Del ID="D2">
<Field1>50</Field1>
<Field2>60</Field2>
<Field3>70</Field3>
<Field4>80</Field4>
</Del>
</Type>
<Type Name="Type2" Code="B">
<Del ID="D1">
<Field1>110</Field1>
<Field2>120</Field2>
<Field3>130</Field3>
<Field4>140</Field4>
</Del>
<Del ID="D3">
<Field1>150</Field1>
<Field2>160</Field2>
<Field3>170</Field3>
<Field4>180</Field4>
</Del>
</Type>
</RATES>
这需要标准化为以下格式,
<RATES>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D1</DelID>
<Field1>10</Field1>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D1</DelID>
<Field2>20</Field2>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D1</DelID>
<Field3>30</Field3>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D1</DelID>
<Field4>40</Field4>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D2</DelID>
<Field1>50</Field1>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D2</DelID>
<Field2>60</Field2>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D2</DelID>
<Field3>70</Field3>
</RATE>
<RATE>
<ID>Type1</ID>
<Code>A</Code>
<DelID>D2</DelID>
<Field4>80</Field4>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D1</DelID>
<Field1>110</Field1>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D1</DelID>
<Field2>120</Field2>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D1</DelID>
<Field3>130</Field3>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D1</DelID>
<Field4>140</Field4>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D3</DelID>
<Field1>50</Field1>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D3</DelID>
<Field2>160</Field2>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D3</DelID>
<Field3>170</Field3>
</RATE>
<RATE>
<ID>Type2</ID>
<Code>B</Code>
<DelID>D3</DelID>
<Field4>180</Field4>
</RATE>
</RATES>
由于我是LINQ的新手,请对此提出建议。谢谢
我不知道是否有任何内置函数可以对XML进行扁平化,但我非常担心它们能够满足您的需求,因为根据您的示例,必须忽略某些属性。
您最好使用LINQ to XML,这样可以非常容易地转换此类文档,而且不需要太多代码。查看我的解决方案:
string origXml = "<RATES ID='"1'" RatesEffectivateDate='"27/02/2014'">'n <Type Name='"Type1'" Code='"A'">'n <Del ID='"D1'">'n <Field1>10</Field1>'n <Field2>20</Field2>'n <Field3>30</Field3>'n <Field4>40</Field4>'n </Del>'n <Del ID='"D2'">'n <Field1>50</Field1>'n <Field2>60</Field2>'n <Field3>70</Field3>'n <Field4>80</Field4>'n </Del>'n </Type>'n <Type Name='"Type2'" Code='"B'">'n <Del ID='"D1'">'n <Field1>110</Field1>'n <Field2>120</Field2>'n <Field3>130</Field3>'n <Field4>140</Field4>'n </Del>'n <Del ID='"D3'">'n <Field1>150</Field1>'n <Field2>160</Field2>'n <Field3>170</Field3>'n <Field4>180</Field4>'n </Del>'n </Type>'n</RATES>";
var xDoc = XDocument.Parse(origXml);
var resDoc = new XDocument(
new XElement("RATES",
xDoc.Element("RATES")
.Elements("Type")
.SelectMany(typeEl =>
typeEl.Elements("Del")
.SelectMany(delEl =>
delEl.Elements()
.Select(fieldEl =>
new XElement("RATE",
new XElement("ID", typeEl.Attribute("Name").Value),
new XElement("Code", typeEl.Attribute("Code").Value),
new XElement("DelID", delEl.Attribute("ID").Value),
new XElement(fieldEl.Name, fieldEl.Value)))))
));
resDoc.Save("transformedDoc.xml", SaveOptions.None);
输出正是您为示例提供的内容。
你可以这样做:
var xmlDocument = XDocument.Load("path");
var rates = new List<XElement>();
foreach (var type in xmlDocument.Descendants("Type"))
{
foreach (var del in type.Elements("Del"))
{
foreach (var field in del.Elements())
{
XElement rate = new XElement("RATE",
new XElement("ID", (string) type.Attribute("Name")),
new XElement("Code", (string) type.Attribute("Code")),
new XElement("DelID", (string) del.Attribute("ID")),
new XElement(field.Name, (string) field));
rates.Add(rate);
}
}
}
XElement root = new XElement("RATES");
root.Add(rates);
root.Save("newFile.xml");
使用LINQ
代替循环的另一种方法,但我认为这是可读性较差的
var xmlDocument = XDocument.Load("path");
var newXML = new XElement("RATES",
xmlDocument.Descendants()
.Where(x => x.Name.ToString().StartsWith("Field"))
.Select(
x =>
new XElement("RATE",
new XElement("ID", (string) x.Parent.Parent.Attribute("Name")),
new XElement("Code", (string) x.Parent.Parent.Attribute("Code")),
new XElement("DelID", (string) x.Parent.Attribute("ID")),
new XElement(x.Name, (string) x))));
newXML.Save("newFile.xml");