通用XML阅读器代码

本文关键字:代码 XML 通用 | 更新日期: 2023-09-27 18:08:32

我有一个程序,它解析三个不同的CrystalReport XML文件(结构相似,但后代级别不同),然后将值填充到一个类中。

下面是第一个例子:

    public static List<VyplatnePasky> DeserialzieRozuctovanieMzdy(ref List<VyplatnePasky> _pasky, string sPath)
    {
        XDocument document = XDocument.Load(sPath);
        var formattedAreaPairReport = from d in document.Descendants("FormattedReport".AddNamespace())
                                                        .Descendants("FormattedAreaPair".AddNamespace())
                                                        .Descendants("FormattedAreaPair".AddNamespace())
                                      select d.Element("FormattedAreaPair".AddNamespace());
        if (formattedAreaPairReport.Count() == 0)
        {
            //empty;
            InsertErrorMessage("<formattedAreaPairReport> contains no data! No Data to parse from.", "DeserialzieRozuctovanieMzdy");
            return _pasky;
        }
        //check if any sequence contains any matching elements
        var GotElements = formattedAreaPairReport.Elements("FormattedAreaPair".AddNamespace()).Where(n=>n.Attribute("Level").Value == "3" && n.Attribute("Type").Value == "Group");
        if (GotElements == null)
        {
            InsertErrorMessage("There are no matching elements under <formattedAreaPairReport>.", "DeserialzieRozuctovanieMzdy");
            return _pasky;
        }
        foreach (XElement xElement in GotElements)
        {
            RozuctovanieMzda_Values(xElement, ref _pasky);
        }
        return _pasky;
    }

下面是第二个(第二个XML文档解析器):

    public static List<VyplatnePasky> DeserializeVyplatnePasky(string sPath)
    {
        List<VyplatnePasky> _pasky = new List<VyplatnePasky>();
        XDocument document = XDocument.Load(sPath);
        var formattedAreaPairReport = from d in document.Descendants("FormattedReport".AddNamespace())
                                      select d.Element("FormattedAreaPair".AddNamespace());
        if (formattedAreaPairReport.Count() == 0)
        {
            //empty;
            InsertErrorMessage("<formattedAreaPairReport> contains no data! No Data to parse from.", "DeserializeVyplatnePasky");
        }
        else
        {
            //sequence contains data
            foreach (XElement xElement in formattedAreaPairReport.Elements("FormattedAreaPair".AddNamespace()))
            {
                VyplatnePasky _paska = new VyplatnePasky();
                VyplatnePasky_Items(xElement, ref _paska);
                _pasky.Add(_paska);
            }
        }
        return _pasky;
    }

从上面的代码中可以看到,所有三种XML解析方法看起来几乎相同;主要的区别是我在后代中有多深,例如formattedAreaPairReport

我想做的是,通过创建可以被所有三个方法使用的泛型void,使这段代码更专业和可重用。

我正在考虑创建多个委托,在那里我将传递我的lambda命令,如:

            var formattedAreaPairReport = ProcessFirstLevel(from d in document.Descendants("FormattedReport".AddNamespace())
                                      select d.Element("FormattedAreaPair".AddNamespace()));

然而,它会变成一个大而混乱的空白。

问题是——这真的是可行的/值得做吗?你能帮帮我吗?

通用XML阅读器代码

您可以使用一些干净的编码技术来DRY代码。试着这样做:

public static List<VyplatnePasky> DeserialzieRozuctovanieMzdy(ref List<VyplatnePasky> _pasky, string sPath)
{
    var formattedAreaPairReport =
    tryToGetItemsFromDocument
    (
        sPath,
        document=>from d in document.Descendants("FormattedReport".AddNamespace())
                  .Descendants("FormattedAreaPair".AddNamespace())
                  .Descendants("FormattedAreaPair".AddNamespace())
                  select d.Element("FormattedAreaPair".AddNamespace()),
        "DeserialzieRozuctovanieMzdy"
    );
    addItemsToVyplatnePasky(formattedAreaPairReport, ref _pasky);
    return _pasky;
}
public static List<VyplatnePasky> DeserializeVyplatnePasky(string sPath)
{
    List<VyplatnePasky> _pasky = new List<VyplatnePasky>();
    var formattedAreaPairReport =
    tryToGetItemsFromDocument
    (
        sPath,
        document=>from d in document.Descendants("FormattedReport".AddNamespace())
                  select d.Element("FormattedAreaPair".AddNamespace()),
        "DeserializeVyplatnePasky"
    );
    addItemsToVyplatnePasky2(formattedAreaPairReport, _pasky);
    return _pasky;
}
private static void addItemsToVyplatnePasky(IEnumerable<XElement> formattedAreaPairReport, ref List<VyplatnePasky> _pasky)
{
    if (formattedAreaPairReport.Count() > 0)
    {
        //check if any sequence contains any matching elements
        var GotElements = formattedAreaPairReport.Elements("FormattedAreaPair".AddNamespace()).Where(n=>n.Attribute("Level").Value == "3" && n.Attribute("Type").Value == "Group");
        if (GotElements == null)
        {
            InsertErrorMessage("There are no matching elements under <formattedAreaPairReport>.", "DeserialzieRozuctovanieMzdy");
            return;
        }
        foreach (XElement xElement in GotElements)
        {
            RozuctovanieMzda_Values(xElement, ref _pasky);
        }
    }
}
private static void addItemsToVyplatnePasky2(IEnumerable<XElement> formattedAreaPairReport, List<VyplatnePasky> _pasky)
{
    foreach (XElement xElement in formattedAreaPairReport.Elements("FormattedAreaPair".AddNamespace()))
    {
        VyplatnePasky _paska = new VyplatnePasky();
        VyplatnePasky_Items(xElement, ref _paska);
        _pasky.Add(_paska);
    }
}
private static IEnumerable<XElement> tryToGetItemsFromDocument(string sPath, Func<XDocument, IEnumerable<XElement>> query, string name)
{
    XDocument document = XDocument.Load(sPath);
    var report = query(document);
    if (report.Count() == 0)
    {
        //empty;
        InsertErrorMessage("<formattedAreaPairReport> contains no data! No Data to parse from.", name);
    }
    return report;
}

本质上,您可以继续分解代码,然后寻找重复的习惯用法来清理。泛型可能会在清理过程中发挥作用,也可能不会。另外,您可能希望给这些方法起一个比我更好的名字,因为我不熟悉这段代码中使用的母语。: -)