2012-01-10 15 views
6

मैंने सी # और लिंक-टू-एक्सएमएल का उपयोग करके कुछ एक्सएमएल फाइलों (यानी, कुछ विशेषताओं/मानों को खोने वाले) को सुधारने के लिए एक उपकरण लिखा था। टूल एक मौजूदा XML फ़ाइल को XDocument ऑब्जेक्ट में लोड करता है। फिर, यह गायब डेटा डालने के लिए नोड के माध्यम से नीचे विश्लेषण करता है। उसके बाद, यह किसी अन्य निर्देशिका में परिवर्तनों को सहेजने के लिए XDocument.Save() को कॉल करता है।XDocument.Save() मेरी इकाइयों को हटाता है

यह सब एक चीज़ को छोड़कर ठीक है: & #xA; एक्सएमएल फ़ाइल में पाठ में मौजूद इकाइयों को एक नए लाइन वर्ण के साथ बदल दिया गया है। इकाई निश्चित रूप से एक नई लाइन का प्रतिनिधित्व करती है, लेकिन मुझे एक्सएमएल में इकाई को संरक्षित करने की आवश्यकता है क्योंकि किसी अन्य उपभोक्ता को इसकी आवश्यकता होती है।

& #xA खोए बिना संशोधित XDocument को सहेजने का कोई तरीका है; इकाइयां?

धन्यवाद।

+1

बदलते हैं जब आप पुराने दस्तावेज़ को लोड करते हैं या जब आप नया सहेजते हैं? –

+0

@ अर्नोल्ड: जब मैं नया सहेजता हूं। – mahdaeng

+0

आदर्श समाधान आपके एक्सएमएल के उपभोक्ता को ठीक करना होगा, ताकि यह एक्सएमएल को सही तरीके से संभाल सके। – svick

उत्तर

10


 इकाइयों को तकनीकी रूप से एक्सएमएल में "संख्यात्मक चरित्र संदर्भ" कहा जाता है, और जब मूल दस्तावेज़ XDocument में लोड किया जाता है तो उन्हें हल किया जाता है। यह आपकी समस्या को सुलझाने में समस्याग्रस्त बनाता है, क्योंकि XDocument लोड होने के बाद असामान्य सफेद जगह (आमतौर पर सादे-पाठ दर्शकों के लिए XML दस्तावेज़ों को स्वरूपित करने के लिए उपयोग किया जाता है) से हल किए गए व्हाइटस्पेस इकाइयों को अलग करने का कोई तरीका नहीं है। इस प्रकार, नीचे केवल तभी लागू होता है जब आपके दस्तावेज़ में कोई महत्वहीन व्हाइटस्पेस न हो।

System.Xml पुस्तकालय एक Entitize को XmlWriterSettings वर्ग के NewLineHandling संपत्ति की स्थापना द्वारा खाली स्थान के संस्थाओं को संरक्षित करने की अनुमति देता है। हालांकि, टेक्स्ट नोड्स के भीतर, यह केवल \r से 
 पर, और \n से 
 को अधिकृत करेगा।

सबसे आसान समाधान XmlWriter कक्षा से प्राप्त करना है और अपने WriteString विधि को ओवरराइड करना है ताकि वे अपने संख्यात्मक चरित्र इकाइयों के साथ व्हाइटस्पेस वर्णों को मैन्युअल रूप से प्रतिस्थापित कर सकें। WriteString विधि को भी जगह है जहां नेट entitizes अक्षर हैं जो इस तरह के वाक्य रचना मार्करों &, <, और >, जो क्रमशः &amp;, &lt;, और &gt; को entitized कर रहे हैं के रूप में पाठ नोड्स, में प्रदर्शित करने की अनुमति नहीं है होता है।

XmlWriter अमूर्त है, इसलिए हम पूर्व वर्ग के सभी अमूर्त तरीकों को लागू करने से बचने के लिए XmlTextWriter से प्राप्त करेंगे।

public class EntitizingXmlWriter : XmlTextWriter 
{ 
    public EntitizingXmlWriter(TextWriter writer) : 
     base(writer) 
    { } 

    public override void WriteString(string text) 
    { 
     foreach (char c in text) 
     { 
      switch (c) 
      { 
       case '\r': 
       case '\n': 
       case '\t': 
        base.WriteCharEntity(c); 
        break; 
       default: 
        base.WriteString(c.ToString()); 
        break; 
      } 
     } 
    } 
} 

तो उत्पादन परिवेश में उपयोग के लिए, आप, c.ToString() भाग को खत्म करना चाहते हैं, क्योंकि यह बहुत अक्षम है: यहाँ एक त्वरित और गंदा कार्यान्वयन है। आप मूल text के सबस्ट्रिंग्स को बैच करके कोड को अनुकूलित कर सकते हैं जिसमें आपके द्वारा अधिकृत किए जाने वाले पात्रों में से कोई भी शामिल नहीं है, और उन्हें एक साथ base.WriteString कॉल में फ़ीड करना शामिल है।

चेतावनी का एक शब्द: निम्नलिखित अनुभवहीन कार्यान्वयन काम नहीं करेगा, आधार के बाद से WriteString विधि &amp; के साथ किसी भी & पात्रों की जगह लेंगे, जिससे \r के कारण &amp;#xA; करने के लिए विस्तारित किया जाना है।

public override void WriteString(string text) 
    { 
     text = text.Replace("\r", "&#xD;"); 
     text = text.Replace("\n", "&#xA;"); 
     text = text.Replace("\t", "&#x9;"); 
     base.WriteString(text); 
    } 

अंत में, एक गंतव्य फ़ाइल या धारा में अपने XDocument को बचाने के लिए, बस निम्नलिखित स्निपेट का उपयोग करें:

using (var textWriter = new StreamWriter(destination)) 
using (var xmlWriter = new EntitizingXmlWriter(textWriter)) 
    document.Save(xmlWriter); 

आशा इस मदद करता है!

संपादित:

public override void WriteString(string text) 
{ 
    // The start index of the next substring containing only non-entitized characters. 
    int start = 0; 

    // The index of the current character being checked. 
    for (int curr = 0; curr < text.Length; ++curr) 
    { 
     // Check whether the current character should be entitized. 
     char chr = text[curr]; 
     if (chr == '\r' || chr == '\n' || chr == '\t') 
     { 
      // Write the previous substring of non-entitized characters. 
      if (start < curr) 
       base.WriteString(text.Substring(start, curr - start)); 

      // Write current character, entitized. 
      base.WriteCharEntity(chr); 

      // Next substring of non-entitized characters tentatively starts 
      // immediately beyond current character. 
      start = curr + 1; 
     } 
    } 

    // Write the trailing substring of non-entitized characters. 
    if (start < text.Length) 
     base.WriteString(text.Substring(start, text.Length - start)); 
} 
+0

यह मैंने कभी देखा है सबसे गहन जवाब में से एक है। मैं इसे आजमाने की कोशिश कर रहा हूं। भले ही यह काम न करे (और शायद यह होगा), आपको मेरा वोट मिल जाएगा। धन्यवाद, डगलस! – mahdaeng

+0

आपका स्वागत है :-) यह न भूलें कि उपरोक्त केवल तभी काम करेगा यदि आपके स्रोत एक्सएमएल में आपके पास महत्वहीन सफेद जगह नहीं है। यदि आपके पास महत्वहीन व्हाइटस्पेस है, तो मैं सुझाव दूंगा कि आप दूसरे उत्तर (नीचे) से कोड का उपयोग करें। – Douglas

0

अपने दस्तावेज़ तुच्छ खाली स्थान के जो आप अपने &#xA; संस्थाओं से अलग करना चाहते हैं, तो आप निम्न का उपयोग कर सकते हैं: संदर्भ के लिए, अधिरोहित WriteString विधि का एक अनुकूलित संस्करण है (बहुत आसान) समाधान: &#xA; चरित्र संदर्भ अस्थायी रूप से किसी अन्य वर्ण (जो आपके दस्तावेज़ में पहले से मौजूद नहीं है) में कनवर्ट करें, अपना एक्सएमएल प्रोसेसिंग करें, और फिर आउटपुट परिणाम में चरित्र को वापस कनवर्ट करें। नीचे दिए गए उदाहरण में, हम निजी चरित्र U+E800 का उपयोग करेंगे।

static string ProcessXml(string input) 
{ 
    input = input.Replace("&#xA;", "&#xE800;"); 
    XDocument document = XDocument.Parse(input); 
    // TODO: Perform XML processing here. 
    string output = document.ToString(); 
    return output.Replace("\uE800", "&#xA;"); 
} 

ध्यान दें कि, के बाद से XDocument निराकरण उनकी संगत यूनिकोड वर्ण को आंकिक केरेक्टर सन्दर्भ, "&#xE800;" संस्थाओं उत्पादन में '\uE800' का संकल्प लिया गया होता।

आमतौर पर, आप यूनिकोड के "निजी उपयोग क्षेत्र" (U+E000 - U+F8FF) से किसी भी कोडपॉइंट का सुरक्षित रूप से उपयोग कर सकते हैं। यदि आप अतिरिक्त सुरक्षित होना चाहते हैं, तो यह जांच करें कि दस्तावेज़ दस्तावेज़ में पहले से मौजूद नहीं है; यदि हां, तो कहा गया सीमा से एक और चरित्र चुनें। चूंकि आप केवल अस्थायी रूप से और आंतरिक रूप से चरित्र का उपयोग करेंगे, इससे कोई फर्क नहीं पड़ता कि आप किस का उपयोग करते हैं। बहुत ही असंभव परिदृश्य में कि दस्तावेज़ में सभी निजी उपयोग वर्ण पहले ही मौजूद हैं, अपवाद फेंक दें; हालांकि, मुझे संदेह है कि यह कभी भी अभ्यास में होगा।

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