获取不是';t分组在一个节点下
本文关键字:一个 节点 获取 | 更新日期: 2023-09-27 18:21:29
我正在升级一个超旧的网页以使用Angular,我有一个网页正在从XML文档加载数据。XML文档目前的布局如下:
<xml>
<PREMout>
<PolicyNumber>12345</PolicyNumber>
<ModeCode>ANN</ModeCode>
<PremFromDate>11/10/2015</PremFromDate>
<PremToDate>12/12/2020</PremToDate>
<AnnualPremium>400.00</AnnualPremium>
<ModePremium>400.00</ModePremium>
<PremFromDate>12/31/2020</PremFromDate>
<PremToDate>12/12/2027</PremToDate>
<AnnualPremium>5000.00</AnnualPremium>
<ModePremium>5000.00</ModePremium>
etc
这四列(PremFromDate
、PremToDate
、AnnualPremium
和ModePremium
)被重复多次。由于它们没有在一个节点内分组。。。我该如何将这些字段组合在一起?
目前,旧页面正在获取所有PremFromDate
字段,并将它们推送到绑定到DataGrid
的列中。它也为其他领域做这件事。这似乎是一种非常危险的显示数据的方式,因为如果出现问题会发生什么?
有人知道如何在不在一个节点中的情况下将这四列分组吗?理想情况下。。。xml将被重写为不完全糟糕,但在这种情况下这不是一个选项:(
您可以使用Linq-to-XML将XML加载到XDocument
中,然后重新排序或重组相应的子节点。
例如,以下将按名称将PREMout
的所有子元素按每个组的第一个元素出现的顺序分组:
public static class XmlPremOutHelper
{
public static void ReorderPremiumElements(TextReader from, TextWriter to)
{
var doc = XDocument.Load(from);
foreach (var node in doc.Descendants("PREMout"))
{
var g = node.Elements().GroupBy(e => e.Name);
foreach (var nodes in g)
{
nodes.Remove();
node.Add(nodes);
}
}
doc.Save(to);
}
}
(这里我从TextReader
流式传输到TextWriter
。)
或者,您可以将每组四个元素重组为一个单独的中间节点,例如PREMoutData
:
public static class XmlPremOutHelper
{
public static void GroupPremiumElements(TextReader from, TextWriter to)
{
var doc = XDocument.Load(from);
foreach (var node in doc.Descendants("PREMout"))
{
var lists = new[] {
node.Elements("PremFromDate").ToList(),
node.Elements("PremToDate").ToList(),
node.Elements("AnnualPremium").ToList(),
node.Elements("ModePremium").ToList(),
};
if (!lists.Skip(1).All(l => l.Count == lists[0].Count))
throw new InvalidOperationException("Unequal list counts");
foreach (var nodes in lists.ZipMany(l => l))
{
nodes.Remove();
node.Add(new XElement("PREMoutData", nodes));
}
}
doc.Save(to);
}
}
public static class EnumerableExtensions
{
// Taken from
// https://stackoverflow.com/questions/17976823/how-to-zip-or-rotate-a-variable-number-of-lists
public static IEnumerable<TResult> ZipMany<TSource, TResult>(
this IEnumerable<IEnumerable<TSource>> source,
Func<IEnumerable<TSource>, TResult> selector)
{
// ToList is necessary to avoid deferred execution
var enumerators = source.Select(seq => seq.GetEnumerator()).ToList();
try
{
while (true)
{
foreach (var e in enumerators)
{
bool b = e.MoveNext();
if (!b)
yield break;
}
// Again, ToList (or ToArray) is necessary to avoid deferred execution
yield return selector(enumerators.Select(e => e.Current).ToList());
}
}
finally
{
foreach (var e in enumerators)
e.Dispose();
}
}
}
在这里,我使用了一个扩展方法ZipMany()
,来自EricLippert的这个答案。
小提琴原型。