2011-07-27 14 views
9

मेरे पास एक एक्सडोकॉल है जो मैं एक बाइट सरणी (टीसीपी/आईपी पर प्राप्त) से बना हूं।लिंक-टू-एक्सएमएल XElement.Remove() अवांछित व्हाइटस्पेस छोड़ देता है

मैं तो विशिष्ट एक्सएमएल नोड्स (XElements) के लिए और XElement.Remove फोन करके Xdocument के बंद मूल्य 'पॉप' यह पुन: प्राप्त करने के बाद() खोज करते हैं। मेरे सभी पार्सिंग पूर्ण होने के बाद, मैं उस XML को लॉग इन करने में सक्षम होना चाहता हूं जिसे मैंने पार्स नहीं किया है (एक्सडी दस्तावेज़ में शेष xml)। समस्या यह है कि अतिरिक्त सफेद जगह है जो तब भी बनी हुई है जब XElement.Remove() को बुलाया जाता है। शेष xml में शेष प्रारूप को संरक्षित करते समय मैं इस अतिरिक्त सफेद जगह को हटाने का सबसे अच्छा तरीका जानना चाहता हूं।

उदाहरण/नमूना कोड

मैं सॉकेट पर निम्नलिखित एक्सएमएल प्राप्त होता है:

<?xml version="1.0"?> 
<catalog> 
    <book id="bk101"> 
     <author>Gambardella, Matthew</author> 
     <title>XML Developer's Guide</title> 
     <genre>Computer</genre> 
     <price>44.95</price> 
     <publish_date>2000-10-01</publish_date> 
     <description>An in-depth look at creating applications with XML.</description> 
    </book> 
</catalog> 

और मैं इस xml पार्स और XElements के एक नंबर को दूर करने के लिए निम्न कोड का उपयोग करें:

private void socket_messageReceived(object sender, MessageReceivedEventArgs e) 
{ 
    XDocument xDoc; 
    try 
    { 
     using (MemoryStream xmlStream = new MemoryStream(e.XmlAsBytes)) 
     using (XmlTextReader reader = new XmlTextReader(xmlStream)) 
     { 
      xDoc = XDocument.Load(reader); 
     } 

     XElement Author = xDoc.Root.Descendants("author").FirstOrDefault(); 
     XElement Title = xDoc.Root.Descendants("title").FirstOrDefault(); 
     XElement Genre = xDoc.Root.Descendants("genre").FirstOrDefault(); 

     // Do something with Author, Title, and Genre here... 

     if (Author != null) Author.Remove(); 
     if (Title != null) Title.Remove(); 
     if (Genre != null) Genre.Remove(); 

     LogUnparsedXML(xDoc.ToString()); 

    } 
    catch (Exception ex) 
    { 
     // Exception Handling here... 
    } 
} 

फिर लॉगून्परस्डएक्सएमएल संदेश को भेजे गए एक्सएमएल की परिणामी स्ट्रिंग होगी:

<?xml version="1.0"?> 
<catalog> 
    <book id="bk101"> 



     <price>44.95</price> 
     <publish_date>2000-10-01</publish_date> 
     <description>An in-depth look at creating applications with XML.</description> 
    </book> 
</catalog> 

इस संक्रमित उदाहरण में यह एक बड़ा सौदा प्रतीत नहीं होता है, लेकिन मेरे वास्तविक अनुप्रयोग में बचे हुए एक्सएमएल बहुत खराब दिखते हैं। मैंने XDocument.ToString अधिभार का उपयोग करने का प्रयास किया है जो किसी भी लाभ के लिए SaveOptions enum लेता है। मैंने xDoc.Save को SaveOptions enum का उपयोग करके फ़ाइल में सहेजने के लिए भी कॉल करने का प्रयास किया है। मैंने कुछ अलग linq प्रश्नों के साथ प्रयोग करने का प्रयास किया जो व्हाइटस्पेस को हटाने का प्रयास करने के लिए XElement.Nodes().OfType<XText>() का उपयोग करता था, लेकिन अक्सर मैं सफेद जगह लेना चाहता था जिसे मैं छुटकारा पाने की कोशिश कर रहा हूं।

सहायता के लिए अग्रिम धन्यवाद।

जो

+0

'ToString() 'कॉल पर' SaveOptions.DisableFormatting' 'पर विकल्प सेट करने का प्रयास करें। –

उत्तर

3

यह एक पोर्टेबल तरह से जवाब देने के लिए आसान नहीं है, क्योंकि समाधान भारी XDocument.Load() कैसे उत्पन्न खाली स्थान के पाठ नोड्स पर निर्भर करता है (और वहाँ है कि चारों ओर एक्सएमएल के लिए LINQ के कई कार्यान्वयन है कि सूक्ष्म विस्तार के बारे में असहमत हो सकता है कर रहे हैं) ।

कहा कि, ऐसा लगता है तुम कभी नहीं <book> तत्वों से पिछले बच्चे (<description>) निकालने जा रहे हैं की तरह। यदि वास्तव में यह मामला है, तो हमें मूल तत्व के समापन टैग के इंडेंटेशन के बारे में चिंता करने की ज़रूरत नहीं है, और हम तत्व और उसके सभी पाठ नोड्स को तब तक हटा सकते हैं जब तक कि हम किसी अन्य तत्व तक नहीं पहुंच जाते। TakeWhile() नौकरी करेगा।

संपादित करें: खैर, यह आप सब के बाद अंतिम संतान को हटाने की जरूरत है। इसलिए, चीजें अधिक जटिल हो जाएगी। नीचे दिए गए कोड निम्नलिखित कलन विधि को लागू करता है:

  • जब तक हम अगले तत्व तक पहुंचने के सभी निम्न पाठ नोड्स निकालें:

    • तत्व अपनी मूल के अंतिम तत्व नहीं है।
  • अन्यथा:
    • निकालें सभी निम्न पाठ नोड्स जब तक हम एक एक नई पंक्ति युक्त मिल जाए,
    • उस नोड केवल एक नई पंक्ति में शामिल हैं:
      • उस नोड निकालें।
    • अन्यथा:
      • केवल रिक्त स्थान न्यू लाइन के बाद पाया युक्त एक नए नोड बनाएँ,
      • मूल नोड के बाद उस नोड डालें,
      • मूल नोड निकालें।
  • तत्व को स्वयं हटाएं।

जिसके परिणामस्वरूप कोड है:

public static void RemoveWithNextWhitespace(this XElement element) 
{ 
    IEnumerable<XText> textNodes 
     = element.NodesAfterSelf() 
       .TakeWhile(node => node is XText).Cast<XText>(); 
    if (element.ElementsAfterSelf().Any()) { 
     // Easy case, remove following text nodes. 
     textNodes.ToList().ForEach(node => node.Remove()); 
    } else { 
     // Remove trailing whitespace. 
     textNodes.TakeWhile(text => !text.Value.Contains("\n")) 
       .ToList().ForEach(text => text.Remove()); 
     // Fetch text node containing newline, if any. 
     XText newLineTextNode 
      = element.NodesAfterSelf().OfType<XText>().FirstOrDefault(); 
     if (newLineTextNode != null) { 
      string value = newLineTextNode.Value; 
      if (value.Length > 1) { 
       // Composite text node, trim until newline (inclusive). 
       newLineTextNode.AddAfterSelf(
        new XText(value.SubString(value.IndexOf('\n') + 1))); 
      } 
      // Remove original node. 
      newLineTextNode.Remove(); 
     } 
    } 
    element.Remove(); 
} 

वहाँ से, आप कर सकते हैं:

if (Author != null) Author.RemoveWithNextWhitespace(); 
if (Title != null) Title.RemoveWithNextWhitespace(); 
if (Genre != null) Genre.RemoveWithNextWhitespace(); 

हालांकि मैं तुम्हें एक पाश एक से तंग आ गया की तरह कुछ के साथ ऊपर की जगह सुझाव है कोड अनावश्यकता से बचने के लिए सरणी या params विधि कॉल।

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