【问题标题】:readElements XML with XmlReader and Linq带有 XmlReader 和 Linq 的 readElements XML
【发布时间】:2011-05-07 10:38:07
【问题描述】:

我的目标是阅读这个 xml file 流:

<?xml version="1.0" encoding="utf-16"?>
<events>
    <header>
        <seq>0</seq>
    </header>
    <body>
        <orderBookStatus>
            <id>100093</id>
            <status>Opened</status>
        </orderBookStatus>
        <orderBook>
            <instrumentId>100093</instrumentId>
            <bids>
                <pricePoint>
                    <price>1357.1</price>
                    <quantity>20</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1357.0</price>
                    <quantity>20</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1356.9</price>
                    <quantity>71</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1356.8</price>
                    <quantity>20</quantity>
                </pricePoint>
            </bids>
            <offers>
                <pricePoint>
                    <price>1357.7</price>
                    <quantity>51</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1357.9</price>
                    <quantity>20</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1358.0</price>
                    <quantity>20</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1358.1</price>
                    <quantity>20</quantity>
                </pricePoint>
                <pricePoint>
                    <price>1358.2</price>
                    <quantity>20</quantity>
                </pricePoint>
            </offers>
            <lastMarketClosePrice>
                <price>1356.8</price>
                <timestamp>2011-05-03T20:00:00</timestamp>
            </lastMarketClosePrice>
            <dailyHighestTradedPrice />
            <dailyLowestTradedPrice />
            <valuationBidPrice>1357.1</valuationBidPrice>
            <valuationAskPrice>1357.7</valuationAskPrice>
            <lastTradedPrice>1328.1</lastTradedPrice>
            <exchangeTimestamp>1304501070802</exchangeTimestamp>
        </orderBook>
    </body>
</events>

我创建(基于此处的帖子:http://blogs.msdn.com/b/xmlteam/archive/2007/03/24/streaming-with-linq-to-xml-part-2.aspx 一个函数

public IEnumerable<XElement> readElements(XmlReader r, string matchName)
    {
        //r.MoveToContent();
        while (r.Read())
        {
            switch (r.NodeType)
            {
                case XmlNodeType.Element:
                    {
                        if (r.Name == matchName)
                        {
                            XElement el = XElement.ReadFrom(r) as XElement;
                            if (el != null)
                                yield return el;
                        } break;
                    }
            }
        }
    }

我打算按以下方式使用它

            IEnumerable<XElement> xBids = readElements(xmlReader, "bids");
            publishPricePoint(xBids, "bids");
            IEnumerable<XElement> xOffers = readElements(xmlReader, "offers");
            publishPricePoint(xOffers, "offers");

其中的方法 publishPricePoint 如下所示:

    public void publishPricePoint(IEnumerable<XElement> ie, string side)
    {
        PricePoint p = new PricePoint();
        var ci = CultureInfo.InvariantCulture.Clone() as CultureInfo;
        ci.NumberFormat.NumberDecimalSeparator = ".";

        var bids = (from b in ie.Elements() select b).ToList();
        foreach (XElement e in bids)
        {

             p.price = decimal.Parse(e.Element("price").Value, ci);
             p.qty = int.Parse(e.Element("quantity").Value, ci);
             OnPricePointReceived(this, new MessageEventArgs(p, side));
        }
    }

问题是,在这段代码中:

            IEnumerable<XElement> xBids = readElements(xmlReader, "bids");
            publishPricePoint(xBids, "bids");
            IEnumerable<XElement> xOffers = readElements(xmlReader, "offers");
            publishPricePoint(xOffers, "offers");

只有前两行有效,即。只能读取出价,不能读取报价。这有什么问题?对我来说,看起来,在读取出价后 XmlReader 消失了。 谢谢你的帮助

================== 其他解决方案=================

  while (xmlReader.Read())
  {
  #region reading bids
            if (xmlReader.IsStartElement("bids"))
            {
                readingBids = true;
                readingOffers = false;
            }

            if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "bids")
            {
                readingBids = false;
                readingOffers = false;
            }

            if (readingBids == true)
            {
                if (xmlReader.IsStartElement("price"))
                    price = xmlReader.ReadElementContentAsDecimal();

                if (xmlReader.IsStartElement("quantity"))
                {
                    qty = xmlReader.ReadElementContentAsInt();
                    OnPricePointReceived(this, new MessageEventArgs(price, qty, "bid"));
                }
            }
            #endregion

            #region reading offers
            if (xmlReader.IsStartElement("offers"))
            {
                readingBids = false;
                readingOffers = true;
            }

            if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "offers")
            {
                readingBids = false;
                readingOffers = false;
            }

            if (readingOffers == true)
            {
                if (xmlReader.IsStartElement("price"))
                    price = xmlReader.ReadElementContentAsDecimal();

                if (xmlReader.IsStartElement("quantity"))
                {
                    qty = xmlReader.ReadElementContentAsInt();
                    OnPricePointReceived(this, new MessageEventArgs(price, qty, "offer"));
                }
            }
 }

【问题讨论】:

  • 您是否尝试过切换这两个语句...所以先出价然后出价?
  • 当然可以。不工作。

标签: c# xml xmlreader


【解决方案1】:

我认为您将不得不关闭并重新打开 XmlReader。它只是处于 EOF 状态。

您的解决方案需要阅读所有内容两次,效率不高。

除非您的 XML 非常大(例如 > 100 MB),否则将其全部读入 XDocument 并使用 Linq 过滤出价和出价会快得多。

编辑:好的,因此您的数据会持续流式传输。这意味着您不能使用单标签过滤器,您将跳过其他过滤器。

  • 基本思想:使用 XElement.ReadFrom() 读取每个元素
  • 将您想要的元素推入(单独的)队列。
  • 您需要异步处理。使用 TPL 或(测试版)异步/等待功能。

【讨论】:

  • 问题是,我无法加载整个 xml,因为它是来自服务器的推送消息,所以我应该持续阅读它。
  • 我还提出了其他解决方案(请参阅已编辑的问题),但不确定这是否更好,因为如果我想阅读更多元素,代码会变得非常大。
  • 一个基本思路:读取每一个元素,用 XElement.ReadFrom() 这个应该怎么做呢?我认为这是我在代码的第一个版本中的目标,但看起来它没有按应有的方式工作......
【解决方案2】:

你为什么不做这样的事情

XDocument document = XDocument.Load(@"XMLFile1.xml"); 

    var bidResults = (from br in document.Descendants("bids") 
                       select br).ToList();  
    var offerResults = (from or in document.Descendants("offers") 
                       select or).ToList(); 

然后您可以使用 foreach (Xelement element in bidResults) 进行迭代以获取所有投标数据以及来自报价的数据

foreach (XElement xElement in returnResult) 
   {       
    Offer off = new Offer();  
    off.price = xElement.Element("price") != null ? xElement.Element("price").Value : "";       
    off.quantity = xElement.Element("quantity") != null ? xElement.Element("quantity").Value : "";            
  }

【讨论】:

  • 我无法将整个文件作为 XDocument 读取,因为它是以流的形式出现的。我必须在它出现时阅读它。我想出了其他解决方案(请参阅已编辑的问题)
猜你喜欢
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多