2010-01-23 8 views
15

ऐसा लगता है कि जब भी मैं एक XMLReader का उपयोग करता हूं, तो मैं परीक्षण के एक समूह के साथ समाप्त होता हूं और यह पता लगाने की कोशिश कर रहा हूं कि मैं जो पढ़ रहा हूं उसके विरुद्ध मैं जो पढ़ रहा हूं, उसके विपरीत मैं जो पढ़ रहा हूं उसके विपरीत मैं जो पढ़ रहा हूं उसके विपरीत। मैं हमेशा इसे अंत में समझता हूं, लेकिन मैं अभी भी कई बार इसका उपयोग करने के बाद, ऐसा लगता हूं कि जब मैं विभिन्न कार्यों को कॉल करता हूं तो वास्तव में एक XMLReader क्या कर रहा है। उदाहरण के लिए, जब मैं पहली बार पढ़ता हूं, यदि यह तत्व प्रारंभ टैग पढ़ता है, तो क्या यह अब तत्व टैग के अंत में है, या तत्व के गुणों को पढ़ने के लिए तैयार है? क्या मैं अभी तक गुणों के मूल्यों को जानता हूं यदि मैं GetAttribute को कॉल करता हूं? अगर मैं इस बिंदु पर ReadStartElement को कॉल करता हूं तो क्या होगा? क्या यह प्रारंभ तत्व को पढ़ना समाप्त कर देगा, या अगले गुणों को छोड़कर, सभी विशेषताओं को छोड़ देगा? क्या होगा यदि मैं कई तत्वों को पढ़ना चाहता हूं - अगले तत्व को पढ़ने का प्रयास करने का सर्वोत्तम तरीका क्या है और यह निर्धारित करें कि उसका नाम क्या है। IsStartElement कार्य के बाद पढ़ा जाएगा, या क्या IStartElement मैंने जो तत्व पढ़ा है उसके बाद नोड के बारे में जानकारी लौटाएगा?मैं कभी भी XMLReader व्यवहार की भविष्यवाणी नहीं कर सकता। समझने पर कोई सुझाव?

जैसा कि आप देख सकते हैं कि मुझे वास्तव में यह समझने की कमी नहीं है कि एक XMLReader इसके पढ़ने के विभिन्न चरणों के दौरान कहां है और विभिन्न राज्यों द्वारा इसका राज्य कैसे प्रभावित होता है। क्या कोई साधारण पैटर्न है जिसे मैंने नोटिस करने में असफल रहा है?

string input = "<machine code=\"01\">The Terminator" + 
    "<part code=\"01a\">Right Arm</part>" + 
    "<part code=\"02\">Left Arm</part>" + 
    "<part code=\"03\">Big Toe</part>" + 
    "</machine>"; 

using (System.IO.StringReader sr = new System.IO.StringReader(input)) 
{ 
    using (XmlTextReader reader = new XmlTextReader(sr)) 
    { 
     reader.WhitespaceHandling = WhitespaceHandling.None; 
     reader.MoveToContent(); 

     while(reader.Read()) 
     { 
     if (reader.Name.Equals("machine") && (reader.NodeType == XmlNodeType.Element)) 
     { 
      Console.Write("Machine code {0}: ", reader.GetAttribute("code")); 
      Console.WriteLine(reader.ReadElementString("machine")); 
     } 
     if(reader.Name.Equals("part") && (reader.NodeType == XmlNodeType.Element)) 
     { 
      Console.Write("Part code {0}: ", reader.GetAttribute("code")); 
      Console.WriteLine(reader.ReadElementString("part")); 
     } 
     } 
    } 
} 

सबसे पहले समस्या, मशीन नोड पूरी तरह से छोड़ दिया जाता है:

यहाँ समस्या (प्रतिक्रियाओं से लिया गया) का एक और उदाहरण है। MoveToContent मशीन तत्व की सामग्री पर जाने लगता है क्योंकि इसे कभी भी पार्स नहीं किया जा सकता है। इसके अलावा, यदि आप MoveToContent को छोड़ते हैं, तो आपको एक त्रुटि मिलती है: "एलिमेंट 'एक अवैध XmlNodeType है।" ReadElementString करने की कोशिश कर रहा है, जिसे मैं काफी समझा नहीं सकता।

अगला समस्या है, पहले भाग तत्व को पढ़ने के दौरान, ReadElementString पढ़ने के बाद अगले भाग तत्व की शुरुआत में पाठक को स्थिति में दिखता है। यह पाठक का कारण बनता है। अगले भाग तत्व की शुरुआत में अगले भाग तत्व को छोड़कर अंतिम भाग तत्व पर कूदने के लिए पढ़ें। तो इस कोड के अंतिम आउटपुट है:

भाग कोड 01a: सही शाखा

भाग कोड 03: बिग पैर की अंगुली

यह है कि मैं कोशिश कर रहा हूँ XMLReader की confusign व्यवहार का एक प्रमुख उदाहरण है समझना।

उत्तर

3

मेरा नवीनतम समाधान (जो मेरे वर्तमान मामले के लिए काम करता है) एक राज्य मशीन को लागू करने में रीड(), IsStartElement (नाम) और GetAttribute (नाम) के साथ चिपकना है।

using (System.Xml.XmlReader xr = System.Xml.XmlTextReader.Create(stm)) 
{ 
    employeeSchedules = new Dictionary<string, EmployeeSchedule>(); 
    EmployeeSchedule emp = null; 
    WeekSchedule sch = null; 
    TimeRanges ranges = null; 
    TimeRange range = null; 
    while (xr.Read()) 
    { 
     if (xr.IsStartElement("Employee")) 
     { 
     emp = new EmployeeSchedule(); 
     employeeSchedules.Add(xr.GetAttribute("Name"), emp); 
     } 
     else if (xr.IsStartElement("Unavailable")) 
     { 
     sch = new WeekSchedule(); 
     emp.unavailable = sch; 
     } 
     else if (xr.IsStartElement("Scheduled")) 
     { 
     sch = new WeekSchedule(); 
     emp.scheduled = sch; 
     } 
     else if (xr.IsStartElement("DaySchedule")) 
     { 
     ranges = new TimeRanges(); 
     sch.daySchedule[int.Parse(xr.GetAttribute("DayNumber"))] = ranges; 
     ranges.Color = ParseColor(xr.GetAttribute("Color")); 
     ranges.FillStyle = (System.Drawing.Drawing2D.HatchStyle) 
      System.Enum.Parse(typeof(System.Drawing.Drawing2D.HatchStyle), 
      xr.GetAttribute("Pattern")); 
     } 
     else if (xr.IsStartElement("TimeRange")) 
     { 
     range = new TimeRange(
      System.Xml.XmlConvert.ToDateTime(xr.GetAttribute("Start"), 
      System.Xml.XmlDateTimeSerializationMode.Unspecified), 
      new TimeSpan((long)(System.Xml.XmlConvert.ToDouble(xr.GetAttribute("Length")) * TimeSpan.TicksPerHour))); 
     ranges.Add(range); 
     } 
    } 
    xr.Close(); 
} 

पढ़ें बाद, IsStartElement सच वापस आ जाएगी अगर आप सिर्फ एक शुरुआत तत्व पढ़ें (optinally तत्व पढ़ के नाम की जाँच), और आप उस तत्व की सभी विशेषताओं तुरंत उपयोग कर सकते हैं। यदि आपको केवल तत्वों और विशेषताओं को पढ़ने की आवश्यकता है, तो यह बहुत सरल है।

प्रश्न में पोस्ट किया गया नया उदाहरण कुछ अन्य चुनौतियों का सामना करता है।

using (System.IO.StringReader sr = new System.IO.StringReader(input)) 
{ 
    using (XmlTextReader reader = new XmlTextReader(sr)) 
    { 
     reader.WhitespaceHandling = WhitespaceHandling.None; 

     while(reader.Read()) 
     { 
     if (reader.Name.Equals("machine") && (reader.NodeType == XmlNodeType.Element)) 
     { 
      Console.Write("Machine code {0}: ", reader.GetAttribute("code")); 
      Console.WriteLine(reader.ReadString()); 
     } 
     if(reader.Name.Equals("part") && (reader.NodeType == XmlNodeType.Element)) 
     { 
      Console.Write("Part code {0}: ", reader.GetAttribute("code")); 
      Console.WriteLine(reader.ReadString()); 
     } 
     } 
    } 
} 

आपको अंत तत्व पढ़ रहे हैं और अगले तत्व की शुरुआत में लंघन (चलो निम्नलिखित पढ़ें से बचने के लिए ReadElementString के बजाय ReadString उपयोग करने के लिए: कि XML को पढ़ने के लिए सही तरीका इस तरह प्रतीत हो रहा है() अंत तत्व पर छोड़ दें ताकि यह अगले प्रारंभ तत्व पर न छोड़ें)। फिर भी यह कुछ भ्रमित और संभावित अविश्वसनीय लगता है, लेकिन यह इस मामले के लिए काम करता है।

कुछ अतिरिक्त विचारों के बाद, मेरी राय यह है कि XMLReader बहुत उलझन में है यदि आप रीड विधि के अलावा अन्य सामग्री को पढ़ने के लिए किसी भी तरीके का उपयोग करते हैं। मुझे लगता है कि अगर आप स्वयं को एक्सएमएल स्ट्रीम से पढ़ने के लिए रीड विधि को सीमित रखते हैं तो यह बहुत आसान है। यह इस प्रकार से नया उदाहरण के साथ काम करेंगे (एक बार फिर से, ऐसा लगता है IsStartElement, getAttribute और पढ़ें कुंजी तरीके हैं, और आप एक राज्य मशीन के साथ खत्म हो):

while(reader.Read()) 
{ 
    if (reader.IsStartElement("machine")) 
    { 
     Console.Write("Machine code {0}: ", reader.GetAttribute("code")); 
    } 
    if(reader.IsStartElement("part")) 
    { 
     Console.Write("Part code {0}: ", reader.GetAttribute("code")); 
    } 
    if (reader.NodeType == XmlNodeType.Text) 
    { 
     Console.WriteLine(reader.Value); 
    } 
} 
+0

+1 स्टिक के साथ स्टिक के लिए +1() –

5

यहां बात है ... मैंने सीरियलाइजेशन कोड (बहुत सी एक्सएमएल प्रोसेसिंग सहित) की एक उचित मात्रा लिखी है, और मैं खुद को में बिल्कुल आपके जैसा ही नाव ढूंढता हूं। मेरे पास मार्गदर्शन का एक बहुत ही सरल टुकड़ा है, इसलिए: नहीं है।

मैं खुशी से एक तरह से एक्सएमएल जल्दी से लिखने के रूप में XmlWriter इस्तेमाल करेंगे, लेकिन मैं IXmlSerializable एक और समय लागू करने के लिए चुनने से पहले गर्म अंगारों पर चलने चाहते हैं - मैं बस एक अलग DTO लिख सकते हैं और है कि में डेटा को मैप चाहते हैं; इसका मतलब है स्कीमा ("मैक्स", "wsdl", आदि के लिए) मुफ्त में आता है।

+0

आप मुझे बता सकते क्या डीटीओ का मतलब पोर पक्ष ? –

+0

डेटा ट्रांसफर ऑब्जेक्ट - http://en.wikipedia.org/wiki/Data_transfer_object –

+0

अनिवार्य रूप से क्रमबद्धता/परिवहन के लिए तैयार एक ऑब्जेक्ट मॉडल - उदाहरण के लिए यदि आपका * मुख्य * ऑब्जेक्ट मॉडल अपरिवर्तनीय है (कोई "सेटर्स") डीटीओ शायद गुणों को पढ़/लिखना है (चूंकि यह कुछ धारावाहिकों के साथ अच्छी तरह से काम करता है), या एक चतुर पदानुक्रम। –

संबंधित मुद्दे