2011-05-04 47 views
6

我是非常新的解析XML,我開始學習linq,我認爲這可能是最好的解決方案。我最感興趣的是性能,因爲我創建的應用程序將讀取股票交易所的價格,這些價格有時可能會非常迅速地變化。 我從服務器接收以下信息:什麼是最快/最有效的方式來閱讀這個XML字典(Linq或其他?)

<?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> 

我的目標是解析的價格點元件

<pricePoint> 
     <price>1358.2</price> 
     <quantity>20</quantity> 
</pricePoint> 

成以下結構的詞典:

Dictionary<double, PriceLevel> 

在價格應該是一個雙和PriceLevel是一類

class PriceLevel 
{ 
    int bid; 
    int offer; 

    public PriceLevel(int b, int o) 
    { 
      bid = b; 
      offer = o; 
    } 


} 

根據元素的不同,每個價格點都存在(要麼是出價或要約),因此應該相應地分配數量,即如果價格點存在於出價中,那麼數量應該被分配給出價,並且0被提供。相反,如果報價中存在價格點,那麼應該分配數量以提供報價,0報價。

我希望我的解釋清楚,但是如果您在理解時有任何問題,請不要猶豫,在評論中要求澄清。 我非常感謝幫助解決這個問題。

+++++++++++++++++++++++++++++++++++++++++ 更新:

我已經深入到我正在嘗試閱讀的流中,而且它不會像我期望的那麼簡單。我發現,該流並不總是包含整個文檔,因此我將不得不使用XmlReader讀取它以持續處理流。在這種情況下,我如何閱讀出價和優惠?我有這樣的事情:

StreamReader sr = new StreamReader(「.. \ .. \ videos.xml」);

 XmlReader xmlReader = XmlReader.Create(sr); 
     while (xmlReader.Read()) 
     { 
      if (xmlReader.HasValue) 
      { 
       OnXmlValue(this, new MessageEventArgs(true, xmlReader.Value));//saxContentHandler.Content(xmlReader.Value); 
      } 
      else 
      { 
       if (xmlReader.IsEmptyElement) 
       { 
        OnStartElement(this, new MessageEventArgs(false, xmlReader.Name)); 
        OnEndElement(this, new MessageEventArgs(false, xmlReader.Name)); 
       } 
       else if (xmlReader.IsStartElement()) 
       { 
        OnStartElement(this, new MessageEventArgs(false, xmlReader.Name)); 
       } 
       else 
       { 
        OnEndElement(this, new MessageEventArgs(false, xmlReader.Name)); 
       } 
      } 
     } 

,但我很努力的元素名稱鏈接到它的價值...即,我怎麼能知道哪些標價點我目前正在讀,如果存在的話在投標或報價? 謝謝你的幫助

+0

什麼是您的價格點的最大準確性?你有他們所有的小數點後1位,在dp之前有4位數字,在你的例子中。這是如何爲您的所有價格點? – 2011-05-04 10:09:30

+0

速度最快有多快?秒,毫秒,微秒? – Ishtar 2011-05-04 10:28:10

+0

我認爲,6位小數的最大精度應該足夠了。至於速度和性能,每秒鐘會有很多類似的消息,所以我至少要說幾毫秒;) – Macin 2011-05-04 11:24:21

回答

3

什麼時候正在使用基於事件的界面,類似於更新中提供的界面,您將需要記住上一個開始元素事件的名稱。通常,爲了跟蹤事件,持有堆棧是值得的。我可能會做類似於以下內容:

public class PriceLevel 
{ 
    private decimal? bid = null; 
    private decimal? offer = null; 

    public decimal? Bid { 
     get { return bid; } 
     set { bid = value; } 
    } 

    public decimal? Offer { 
     get { return offer; } 
     set { offer = value; } 
    } 
} 

public delegate void OnPriceChange(long instrumentId, Dictionary<decimal, PriceLevel> prices); 

public class MainClass 
{ 
    private Stack<String> xmlStack = new Stack<String>(); 
    private Dictionary<decimal, PriceLevel> prices = new Dictionary<decimal, PriceLevel>(); 
    private bool isBids = false; 
    private decimal? currentPrice = null; 
    private long instrumentId; 
    private OnPriceChange _priceChangeCallback; 

    public void MainClass(OnPriceChange priceChangeCallback) { 
     this._priceChangeCallback = priceChangeCallback; 
    } 

    public void XmlStart(object source, MessageEventArgs args) { 
     xmlStack.Push(args.Value); 

     if (!isBids && "bids" == args.Value) { 
      isBids = true; 
     } 
    } 

    public void XmlEnd(object source, MessageEventArgs args) { 
     xmlStack.Pop(); 

     if (isBids && "bids" == args.Value) { 
      isBids = false; 
     } 

     // Finished parsing the orderBookEvent 
     if ("orderBook" == args.Value) { 
      _priceChangeCallback(instrumentId, prices); 
     } 
    } 

    public void XmlContent(object source, MessageEventArgs args) { 

     switch (xmlStack.Peek()) { 
     case "instrumentId": 
      instrumentId = long.Parse(args.Value); 
      break; 

     case "price": 
      currentPrice = decimal.Parse(args.Value); 
      break; 

     case "quantity": 

      if (currentPrice != null) { 
       decimal quantity = decimal.Parse(args.Value); 

       if (prices.ContainsKey(currentPrice)) { 
        prices[currentPrice] = new PriceLevel(); 
       } 
       PriceLevel priceLevel = prices[currentPrice]; 

       if (isBids) { 
        priceLevel.Bid = quantity; 
       } else { 
        priceLevel.Offer = quantity; 
       } 
      } 
      break; 
     } 
    } 
} 
+0

謝謝邁克爾,這個非常有用的答案! – Macin 2011-05-11 20:22:47

0

首先,我相信你用字典的方法會導致錯誤。如果沒有錯,字典不能有相同的密鑰,所以既然你使用價格作爲關鍵,那麼你很可能會遇到這個問題。

我不能說速度,你必須測試。但到目前爲止,XDocument對我來說運行良好。
使用的XDocument,加載整個XML消息成變量,例如

XDocument doc = XDocument.Load(message); 

隨着文檔,你可以使用LINQ到它們分成買入價和賣出。

一旦你做到這一點,應出示您的數據,你已經得到了價格,並把他們分開成買入價和賣出

+0

+1關鍵衝突,-1表示XDocument,不知道它是否最有效。 – 2011-05-04 10:36:52

2

首先你需要獲得所有優惠的所有投標沒有問題,

XDocument xmlDoc = XDocument.Load("TestFile.xml"); 


var bids = (from b in xmlDoc.Descendants("bids") 
      select b).ToList(); 

var offers = (from o in xmlDoc.Descendants("offers") 
      select o).ToList(); 

那麼你只是迭代throgh出價和優惠,並將它們添加到字典中......但是,因爲有人在此之前出售過......你可能會遇到這樣的問題:如果價格水平具有相同的價格,它將同時具有出價和出價設置

來迭代throgugh l IST你只是這樣做

foreach (XElement e in bids) 
{ 
    price = e.Element("price").Value; 
    quantity = e.Element("quantity").Value; 
    dictionary.add(price, new PriceLevel(quantity,null); 
} 

您提供做...但再次...。你可能要檢查,如果該鍵已經存在相同...

0

我設法得到這樣的事情:

public void messageParser() 
    { 
     int i = 0; 
     bool readingBids = false; 
     bool readingOffers = false; 
     decimal price=0; 
     int qty = 0; 

     StreamReader sr = new StreamReader("..\\..\\sampleResponse.xml"); 

     XmlReader xmlReader = XmlReader.Create(sr); 
     DateTime startTime = DateTime.Now; 
     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")); 
       } 
      } 
      #endregion 
     } 
     DateTime stopTime = DateTime.Now; 
     Console.WriteLine("time: {0}",stopTime - startTime); 
     Console.ReadKey(); 
    } 
} 

這是一個適當的解決方案的問題?我有一個關於這段代碼有些疑惑:

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

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

我只火OnPricePointReceived事件,當我設法閱讀的價格和數量。但是,有可能,沒有數量的給定價格(或不)。如何執行調用,以避免基於不完整消息的錯誤?

相關問題