readElements XML с помощью XmlReader и Linq - PullRequest
0 голосов
/ 07 мая 2011

Моя цель - прочитать этот xml файл stream:

<?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"));
                }
            }
 }

Ответы [ 2 ]

3 голосов
/ 07 мая 2011

Я думаю, вам придется закрыть и снова открыть XmlReader. Это просто в состоянии EOF.

Ваше решение требует прочитать все дважды, не слишком эффективно.

Если ваш XML не очень большой (например,> 100 МБ), было бы намного быстрее прочитать все это в XDocument и отфильтровать предложения и предложения с Linq.

Редактировать: ОК, поэтому ваши данные постоянно передаются. Это означает, что вы не можете использовать фильтр с одним тегом, вы пропустите другие.

  • Основная идея: читать каждый элемент с помощью XElement.ReadFrom ()
  • помещать нужные элементы в (отдельные) очереди.
  • вам понадобится асинхронная обработка. Используйте функции TPL или (бета) асинхронные / ожидающие.
1 голос
/ 07 мая 2011

Почему бы вам не сделать что-то подобное

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 : "";            
  }
...