获取未在节点

时间:2015-11-10 21:48:56

标签: c# angularjs xml

我正在升级超级旧网页以使用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将被重写为不完全吮吸,但这不是这种情况的选项:(

1 个答案:

答案 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