2009-03-24 14 views
48

मैं एक सर्वर से जीएमएल-आधारित एक्सएमएल स्कीमा (नीचे नमूना) में "फीचर्स" को पुनः प्राप्त करने के लिए सी # में एक जीआईएस क्लाइंट टूल लिख रहा हूं। निष्कर्ष 100,000 फीचर्स तक सीमित हैं।सी # कोड में एक्सएमएल (बड़े) एक्सएमएल का सबसे अच्छा तरीका क्या है?

मैं guestimate कि सबसे बड़ा extract.xml 150 मेगाबाइट है, तो जाहिर है डोम पारसर्स बाहर मैं XmlSerializer और XSD.EXE उत्पन्न बाइंडिंग --OR-- XmlReader और एक हाथ के बीच तय करने की कोशिश कर रहा है कर रहे हैं के आसपास हो सकती है तैयार वस्तु ग्राफ।

या शायद एक बेहतर तरीका है जिसे मैंने अभी तक नहीं माना है? XLINQ की तरह, या ????

कृपया कोई मुझे मार्गदर्शन कर सकता है? विशेष रूप से किसी दिए गए दृष्टिकोण की स्मृति दक्षता के संबंध में। यदि नहीं, तो मुझे दोनों समाधानों को "प्रोटोटाइप" करना होगा और उन्हें एक साथ-साथ प्रोफाइल करना होगा।

मैं .NET में कच्चे झींगा का थोड़ा सा हूँ। किसी भी मार्गदर्शन की काफी सराहना की जाएगी।

धन्यवाद। कीथ।


नमूना XML - तक प्रति सुविधा 234,600 coords तक उनमें से 100,000, के।

<feature featId="27168306" fType="vegetation" fTypeId="1129" fClass="vegetation" gType="Polygon" ID="0" cLockNr="51598" metadataId="51599" mdFileId="NRM/TIS/VEGETATION/9543_22_v3" dataScale="25000"> 
    <MultiGeometry> 
    <geometryMember> 
     <Polygon> 
     <outerBoundaryIs> 
      <LinearRing> 
      <coordinates>153.505004,-27.42196 153.505044,-27.422015 153.503992 .... 172 coordinates omitted to save space ... 153.505004,-27.42196</coordinates> 
      </LinearRing> 
     </outerBoundaryIs> 
     </Polygon> 
    </geometryMember> 
    </MultiGeometry> 
</feature> 
+0

कुछ हद तक एक देर से उत्तर: SAX/स्टैक्स स्ट्रीमिंग पार्सिंग उपयोगीता में सीमित है, vtd-xml का प्रयास करें, जो डीओएम –

उत्तर

53

बड़े XML दस्तावेज़ों को पार्स करने के लिए XmlReader का उपयोग करें। XmlReader एक्सएमएल डेटा के लिए तेज़, अग्रेषित, गैर-कैश पहुंच प्रदान करता है। (फॉरवर्ड-केवल इसका मतलब है कि आप एक्सएमएल फाइल को शुरुआत से अंत तक पढ़ सकते हैं लेकिन फ़ाइल में पीछे नहीं जा सकते हैं।) XmlReader स्मृति की थोड़ी मात्रा का उपयोग करता है, और एक सरल सैक्स रीडर का उपयोग करने के बराबर है।

using (XmlReader myReader = XmlReader.Create(@"c:\data\coords.xml")) 
    { 
     while (myReader.Read()) 
     { 
      // Process each node (myReader.Value) here 
      // ... 
     } 
    } 

आप XmlReader का उपयोग आकार में 2 गीगाबाइट्स (GB) तक की फ़ाइलों को संसाधित करने के लिए कर सकते हैं।

रेफरी: How to read XML from a file by using Visual C#

+4

आईआईआरसी, .NET 2.0 के बाद 1/5 का उपयोग करता है, एमएस XmlTextReader के बजाय सीधे XmlReader क्लास का उपयोग करने की अनुशंसा करता है। – Cerebrus

+0

@ सेरेब्रस और मिच: धन्यवाद सज्जनो। मैंने जो कुछ सोचा था, वह काफी है, लेकिन संभावित रूप से गलत रास्ते को पछाड़ने वाले दिनों को बर्बाद करने से पहले दूसरी (सूचित) राय प्राप्त करना वास्तव में बहुत अच्छा है। अत्यधिक सराहनीय! – corlettk

+2

सीएफ में भी विशेष सीटीआर का उपयोग करें। XmlReader.Create के रूप में इसे अनुकूलित किया गया है और इसका उपयोग करने के लिए याद रखें .किप() उन तत्वों को छोड़ने के लिए जो अनिच्छुक हैं! – Quibblesome

6

एक SAX पार्सर आप जो खोज रहे हैं हो सकता है। SAX को पूरे दस्तावेज़ को स्मृति में पढ़ने की आवश्यकता नहीं है - यह इसके माध्यम से बढ़ती है और आपको तत्वों को संसाधित करने की अनुमति देती है। अगर वहाँ नेट में उपलब्ध कराई गई एक SAX पार्सर है मैं नहीं जानता, लेकिन वहाँ कुछ खुला स्रोत विकल्प है कि अपने आप को देखो सकता है:

यहाँ एक संबंधित पोस्ट :

+1

सैक्स वी XmlTextReader के प्रदर्शन की तुलना करना दिलचस्प होगा - किसी ने भी इस – MrTelly

+0

को आजमाया है, मुझे भी दिलचस्पी होगी, मैंने उनकी तुलना नहीं की है –

+0

.NET मूल सैक्स पार्सर प्रदान नहीं करता है, लेकिन मैंने एक आर्कटिकल पढ़ा है (स्लैशडॉट में, मुझे लगता है) जो दिखाता है कि XmlReader "primitives" का उपयोग करके अपने स्वयं के SAX-parser को रोल करना कितना आसान था। – corlettk

12

बस सारांशित करने के लिए, और उत्तर को किसी भी व्यक्ति के लिए थोड़ा और स्पष्ट बनाएं जो Google में यह धागा पाता है।

नेट 2 XmlTextReader से पहले सबसे स्मृति कुशल XML पार्सर मानक एपीआई में उपलब्ध था (thanx मिच ;-)

नेट 2 पेश किया XmlReader वर्ग जो बेहतर फिर से है यह एक आगे की केवल तत्व है इटरेटर (एक स्टैक्स पार्सर की तरह थोड़ा)।(थेंक्स सेरेब्रस ;-)

और याद रखें कि किसी भी एक्सएमएल इंस्टेंस के किड्स में 500k से बड़ा होने की संभावना है, डोम का उपयोग न करें!

चीयर्स सब। कीथ।

15

असत 14 मई 200 9: मैंने एक हाइब्रिड दृष्टिकोण का उपयोग करने के लिए स्विच किया है ... नीचे कोड देखें।

इस संस्करण में दोनों के फायदे के सबसे:
    * XmlReader/XmlTextReader (स्मृति क्षमता -> गति); और
    * XmlSerializer (कोड-जेन -> विकास उन्मूलन और लचीलापन)।

यह दस्तावेज़ के माध्यम से पुन: प्रयास करने के लिए XmlTextReader का उपयोग करता है, और "doclets" बनाता है जो XmlDerializer और XSD.EXE के साथ जेनरेट की गई "एक्सएमएल बाध्यकारी" कक्षाओं का उपयोग करके deserializes।

मुझे लगता है कि यह नुस्खा सार्वभौमिक रूप से लागू है, और यह तेज़ है ... मैं लगभग 7 सेकंड में 56,000 जीएमएल सुविधाओं वाले 201 एमबी एक्सएमएल दस्तावेज़ को पार्स कर रहा हूं ... इस एप्लिकेशन के पुराने वीबी 6 कार्यान्वयन में मिनट लग गए (या यहां तक ​​कि घंटों) बड़े निष्कर्षों का विश्लेषण करने के लिए ... तो मैं जाने के लिए अच्छा लग रहा हूँ।

एक बार फिर, बिग आपके मूल्यवान समय दान करने के लिए फोरमेट्स के लिए धन्यवाद। मैं वास्तव में इसकी प्रशंसा करता हूँ।

चीयर्स सब। कीथ।

using System; 
using System.Reflection; 
using System.Xml; 
using System.Xml.Serialization; 
using System.IO; 
using System.Collections.Generic; 

using nrw_rime_extract.utils; 
using nrw_rime_extract.xml.generated_bindings; 

namespace nrw_rime_extract.xml 
{ 
    internal interface ExtractXmlReader 
    { 
     rimeType read(string xmlFilename); 
    } 

    /// <summary> 
    /// RimeExtractXml provides bindings to the RIME Extract XML as defined by 
    /// $/Release 2.7/Documentation/Technical/SCHEMA and DTDs/nrw-rime-extract.xsd 
    /// </summary> 
    internal class ExtractXmlReader_XmlSerializerImpl : ExtractXmlReader 
    { 
     private Log log = Log.getInstance(); 

     public rimeType read(string xmlFilename) 
     { 
      log.write(
       string.Format(
        "DEBUG: ExtractXmlReader_XmlSerializerImpl.read({0})", 
        xmlFilename)); 
      using (Stream stream = new FileStream(xmlFilename, FileMode.Open)) 
      { 
       return read(stream); 
      } 
     } 

     internal rimeType read(Stream xmlInputStream) 
     { 
      // create an instance of the XmlSerializer class, 
      // specifying the type of object to be deserialized. 
      XmlSerializer serializer = new XmlSerializer(typeof(rimeType)); 
      serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode); 
      serializer.UnknownAttribute += 
       new XmlAttributeEventHandler(handleUnknownAttribute); 
      // use the Deserialize method to restore the object's state 
      // with data from the XML document. 
      return (rimeType)serializer.Deserialize(xmlInputStream); 
     } 

     protected void handleUnknownNode(object sender, XmlNodeEventArgs e) 
     { 
      log.write(
       string.Format(
        "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}", 
        e.LineNumber, e.LinePosition, e.Name, e.Text)); 
     } 

     protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e) 
     { 
      log.write(
       string.Format(
        "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'", 
        e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value)); 
     } 

    } 

    /// <summary> 
    /// xtractXmlReader provides bindings to the extract.xml 
    /// returned by the RIME server; as defined by: 
    /// $/Release X/Documentation/Technical/SCHEMA and 
    /// DTDs/nrw-rime-extract.xsd 
    /// </summary> 
    internal class ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl : 
     ExtractXmlReader 
    { 
     private Log log = Log.getInstance(); 

     public rimeType read(string xmlFilename) 
     { 
      log.write(
       string.Format(
        "DEBUG: ExtractXmlReader_XmlTextReaderXmlSerializerHybridImpl." + 
        "read({0})", 
        xmlFilename)); 

      using (XmlReader reader = XmlReader.Create(xmlFilename)) 
      { 
       return read(reader); 
      } 

     } 

     public rimeType read(XmlReader reader) 
     { 
      rimeType result = new rimeType(); 
      // a deserializer for featureClass, feature, etc, "doclets" 
      Dictionary<Type, XmlSerializer> serializers = 
       new Dictionary<Type, XmlSerializer>(); 
      serializers.Add(typeof(featureClassType), 
       newSerializer(typeof(featureClassType))); 
      serializers.Add(typeof(featureType), 
       newSerializer(typeof(featureType))); 

      List<featureClassType> featureClasses = new List<featureClassType>(); 
      List<featureType> features = new List<featureType>(); 
      while (!reader.EOF) 
      { 
       if (reader.MoveToContent() != XmlNodeType.Element) 
       { 
        reader.Read(); // skip non-element-nodes and unknown-elements. 
        continue; 
       } 

       // skip junk nodes. 
       if (reader.Name.Equals("featureClass")) 
       { 
        using (
         StringReader elementReader = 
          new StringReader(reader.ReadOuterXml())) 
        { 
         XmlSerializer deserializer = 
          serializers[typeof (featureClassType)]; 
         featureClasses.Add(
          (featureClassType) 
          deserializer.Deserialize(elementReader)); 
        } 
        continue; 
        // ReadOuterXml advances the reader, so don't read again. 
       } 

       if (reader.Name.Equals("feature")) 
       { 
        using (
         StringReader elementReader = 
          new StringReader(reader.ReadOuterXml())) 
        { 
         XmlSerializer deserializer = 
          serializers[typeof (featureType)]; 
         features.Add(
          (featureType) 
          deserializer.Deserialize(elementReader)); 
        } 
        continue; 
        // ReadOuterXml advances the reader, so don't read again. 
       } 

       log.write(
        "WARNING: unknown element '" + reader.Name + 
        "' was skipped during parsing."); 
       reader.Read(); // skip non-element-nodes and unknown-elements. 
      } 
      result.featureClasses = featureClasses.ToArray(); 
      result.features = features.ToArray(); 
      return result; 
     } 

     private XmlSerializer newSerializer(Type elementType) 
     { 
      XmlSerializer serializer = new XmlSerializer(elementType); 
      serializer.UnknownNode += new XmlNodeEventHandler(handleUnknownNode); 
      serializer.UnknownAttribute += 
       new XmlAttributeEventHandler(handleUnknownAttribute); 
      return serializer; 
     } 

     protected void handleUnknownNode(object sender, XmlNodeEventArgs e) 
     { 
      log.write(
       string.Format(
        "XML_ERROR: Unknown Node at line {0} position {1} : {2}\t{3}", 
        e.LineNumber, e.LinePosition, e.Name, e.Text)); 
     } 

     protected void handleUnknownAttribute(object sender, XmlAttributeEventArgs e) 
     { 
      log.write(
       string.Format(
        "XML_ERROR: Unknown Attribute at line {0} position {1} : {2}='{3}'", 
        e.LineNumber, e.LinePosition, e.Attr.Name, e.Attr.Value)); 
     } 
    } 
} 
1

बस XmlReader उपयोग का एक उदाहरण के रूप में इस सरल विस्तार विधि जोड़ना चाहते थे (जैसा कि मिच जवाब):

public static bool SkipToElement (this XmlReader xmlReader, string elementName) 
{ 
    if (!xmlReader.Read()) 
     return false; 

    while (!xmlReader.EOF) 
    { 
     if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == elementName) 
      return true; 

     xmlReader.Skip(); 
    } 

    return false; 
} 

और उपयोग:

using (var xml_reader = XmlReader.Create (this.source.Url)) 
{ 
    if (!SkipToElement (xml_reader, "Root")) 
     throw new InvalidOperationException ("XML element \"Root\" was not found."); 

    if (!SkipToElement (xml_reader, "Users")) 
     throw new InvalidOperationException ("XML element \"Root/Users\" was not found."); 

    ... 
} 
+0

अच्छा ... एक सुझाया गया सुधार: अनुपस्थिति अगर मौजूदा तत्व हमेशा चालू ऑपरेशन के लिए टर्मिनल है (यह हमारे पाठक को ईओएफ को छोड़ दिया गया है) तो झूठी वापसी के बजाय सीधे SkipTo में अपवाद फेंक दें ...आपके पास रिपोर्ट करने के लिए मांगा गया नाम नाम है, इसलिए त्रुटि संदेशों में खुद को दोहराने के बजाय इसका उपयोग करें। – corlettk

+0

हाँ, आप सही हैं। यह सिर्फ मेरे विशिष्ट मामले में है, मुझे मिस्ड एलिमेंट के पूर्ण पथ को बताने की ज़रूरत है, न केवल इसका नाम। –

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

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