我正在升级超级旧网页以使用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将被重写为不完全吮吸,但这不是这种情况的选项:(
答案 0 :(得分:1)
您可以使用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();
}
}
}
我在this answer Eric Lippert使用fiddle的扩展方法ZipMany()
。
原型partition。