获取不是';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

这四列(PremFromDatePremToDateAnnualPremiumModePremium)被重复多次。由于它们没有在一个节点内分组。。。我该如何将这些字段组合在一起?

目前,旧页面正在获取所有PremFromDate字段,并将它们推送到绑定到DataGrid的列中。它也为其他领域做这件事。这似乎是一种非常危险的显示数据的方式,因为如果出现问题会发生什么?

有人知道如何在不在一个节点中的情况下将这四列分组吗?理想情况下。。。xml将被重写为不完全糟糕,但在这种情况下这不是一个选项:(

获取不是';t分组在一个节点下

您可以使用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的这个答案。

小提琴原型。