【问题标题】:Efficient Parsing of XML高效解析 XML
【发布时间】:2016-05-29 05:46:05
【问题描述】:

早安,

我正在用 C# .Net 编写一个程序来管理我商店的产品,

通过给定的链接,我可以检索一个 XML 文件,其中包含我可以在我的店面上列出的所有可能的产品。

XML 结构如下所示:

<Product StockCode="103-10440">
    <lastUpdated><![CDATA[Fri, 20 May 2016 17:00:03 GMT]]></lastUpdated>
    <StockCode><![CDATA[103-10440]]></StockCode>
    <Brand><![CDATA[3COM]]></Brand>
    <BrandID><![CDATA[14]]></BrandID>
    <ProdName><![CDATA[BIG FLOW BLOWING JUNCTION FLEX BLOCK, TAKES 32, 40]]>     </ProdName>
    <ProdDesc/>
    <Categories>
        <TopCat><![CDATA[Accessories]]></TopCat>
        <TopCatID><![CDATA[24]]></TopCatID>
    </Categories>
    <ProdImg/>
    <ProdPriceExclVAT><![CDATA[30296.79]]></ProdPriceExclVAT>
    <ProdQty><![CDATA[0]]></ProdQty>
    <ProdExternalURL><![CDATA[http://pinnacle.eliance.co.za/#!/product/4862]]></ProdExternalURL>
</Product>

这是我正在寻找的条目:

  • 上次更新时间
  • 股票代码
  • 品牌
  • 产品名称
  • 产品描述
  • TopCat
  • ProdImg
  • ProdPriceExclVAT
  • 产品数量
  • ProdExternalURL

这一切都很好处理,事实上我做到了:

public ProductList Parse() {

    XmlDocument doc = new XmlDocument();
    doc.Load(XMLLink);

    XmlNodeList ProductNodeList = doc.GetElementsByTagName("Product");
    foreach (XmlNode node in ProductNodeList) {
        Product Product = new Product();

        for (int i = 0; i < node.ChildNodes.Count; i++) {
            if (node.ChildNodes[i].Name == "StockCode") {
                Product.VariantSKU = Convert.ToString(node.ChildNodes[i].InnerText);
            }
            if (node.ChildNodes[i].Name == "Brand") {
                Product.Vendor = Convert.ToString(node.ChildNodes[i].InnerText);
            }
            if (node.ChildNodes[i].Name == "ProdName") {
                Product.Title = Convert.ToString(node.ChildNodes[i].InnerText);
                Product.SEOTitle = Product.Title;
                Product.Handle = Product.Title;
            }
            if (node.ChildNodes[i].Name == "ProdDesc") {
                Product.Body = Convert.ToString(node.ChildNodes[i].InnerText);
                Product.SEODescription = Product.Body;
                if (Product.Body == "") {
                    Product.Body = "ERROR";
                    Product.SEODescription = "ERROR";
                }
            }
            if (node.ChildNodes[i].Name == "Categories") {
                if (!tempList.Categories.Contains(node.ChildNodes[i].ChildNodes[0].InnerText)) {
                    if (!tempList.Categories.Contains("All")) {
                        tempList.Categories.Add("All");
                    }
                        tempList.Categories.Add(node.ChildNodes[i].ChildNodes[0].InnerText);
                }

                Product.Type = Convert.ToString(node.ChildNodes[i].ChildNodes[0].InnerText);
            }
            if (node.ChildNodes[i].Name == "ProdImg") {
                Product.ImageSrc = Convert.ToString(node.ChildNodes[i].InnerText);
                if (Product.ImageSrc == "") {
                    Product.ImageSrc = "ERROR";
                }
                Product.ImageAlt = Product.Title;
            }
            if (node.ChildNodes[i].Name == "ProdPriceExclVAT") {
                float baseprice = float.Parse(node.ChildNodes[i].InnerText);
                double Costprice = ((baseprice * 0.14) + (baseprice * 0.15) + baseprice);
                Product.VariantPrice = Costprice.ToString("0.##");
            }
        }
        Product.Supplier = "Pinnacle";
        if (!tempList.Suppliers.Contains(Product.Supplier)) {
            tempList.Suppliers.Add(Product.Supplier);
        }
        tempList.Products.Add(Product);
        }
    return tempList;
    }
}

但问题是,这种方式大约需要 10 秒才能完成,而这只是我必须解析的多个此类文件中的第一个。

我正在寻找最有效的方法来解析这个 XML 文件,获取我上面提到的所有字段的数据。

编辑: 我在使用预先下载的文件副本运行时以及在运行时从服务器下载文件时对代码进行了基准测试:

  • 使用本地副本:5 秒。

  • 没有本地副本:7.30 秒。

【问题讨论】:

  • 这里有点可疑。这不应该花费10s。你单独计时那个功能?这个 XML 文件有多大?顺便说一句,您可以将node.ChildNodes[i].Name 放入开关;如果您已经找到匹配项,则无需多次检查名称。
  • XML 文件大约 82k 行,文件大小为 3.2MB - 我正在从网络链接中检索所述文件。
  • 时钟下载时间与解析xml的时间分开
  • @KazutoKirigaya 我在不到一分钟的时间内使用 XElement.Load("filename") 加载了一个 1.2GB 的文件,慢的部分很可能是下载部分而不是解析。 82kb 在今天是“非常非常小”,我建议使用 linq to XML (XElement/XDocument) 而不是旧的 XmlDocument 对象
  • 在使用 XmlReader 重写之前倾听人们的声音(这有助于内存消耗 - 解析性能很少见) - 找出当前代码速度变慢的真正原因。

标签: c# xml optimization


【解决方案1】:

对于大型 XML 文件,您必须使用 XmlReader。下面的代码将一次读取一个产品。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create("filename");
            while(!reader.EOF)
            {
                if (reader.Name != "Product")
                {
                    reader.ReadToFollowing("Product");
                }
                if (!reader.EOF)
                {
                    XElement product = (XElement)XElement.ReadFrom(reader);
                    string lastUpdated = (string)product.Element("lastUpdated");
                }
            }
        }
    }
}

【讨论】:

  • 3 MB 不是太大 IMO
  • @jdweng ,这是最有效的方法吗? - 用这个替换我当前的解决方案并对其进行测试。
  • @jdweng,对不起,如果这是一个简单的问题,但我该如何获得我想要获得的嵌套属性 ( TopCat ) - 它与其他属性相同吗?
  • 代码行数不多。当读取多个 3MB 的文件时会开始使用大量内存并最终开始变慢。我的代码确实使用大量内存来一次读取一个元素。唯一确定的是通过测量时间来进行台架测试。
  • 使用后代而不是元素:product.Descendants("TopCat").FirstOrDefault() 和 product.Descendants("TopCatID").FirstOrDefault()
猜你喜欢
  • 1970-01-01
  • 2018-11-26
  • 2012-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多