2012-03-26 10 views
8

हटाने के लिए मैं अनुच्छेद को हटाने की कोशिश कर रहा हूं (मैं ओपनएक्सएमएल का उपयोग कर .docx फ़ाइल से docx टेम्पलेट जैसी फ़ाइल से पीढ़ी करने के लिए कुछ प्लेसहोल्डर टेक्स्ट का उपयोग कर रहा हूं), लेकिन जब भी मैं पैराग्राफ को हटा देता हूं तो यह फ़ोरैच लूप को तोड़ देता है मैं फिर से शुरू करने के लिए उपयोग कर रहा हूँ।सी # ओपनएक्सएमएल अनुच्छेद

MainDocumentPart mainpart = doc.MainDocumentPart; 
IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants(); 

foreach(OpenXmlElement elem in elems){ 
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##") 
    { 
     Run run = (Run)elem.Parent; 
     Paragraph p = (Paragraph)run.Parent; 
     p.RemoveAllChildren(); 
     p.Remove(); 
    } 
} 

यह काम करता है, मेरी जगह धारक और पैरा को हटा यह, में है लेकिन foreach पाश पुनरावृत्ति बंद हो जाता है। और मुझे अपने foreach पाश में करने के लिए और अधिक चीजों की जरूरत है।

इस ठीक OpenXML का उपयोग कर सी # में पैरा दूर करने के लिए रास्ता नहीं है और क्यों मेरे foreach पाश रोक या यह कैसे बंद नहीं बनाने के लिए है? धन्यवाद।

उत्तर

10

यह "हैलोवीन समस्या" है, इसलिए कहा जाता है क्योंकि यह हेलोवीन पर कुछ डेवलपर्स द्वारा देखा गया था, और यह उनके लिए डरावना लग रहा था। यह एक ही समय में अनिवार्य कोड (नोड्स को हटाने) के साथ घोषणात्मक कोड (प्रश्न) का उपयोग करने की समस्या है। यदि आप इसके बारे में सोचते हैं, तो आप एक लिंक्ड सूची के बावजूद पुनरावृत्त कर रहे हैं, और यदि आप लिंक की गई सूची में नोड्स को हटाना शुरू करते हैं, तो आप पूरी तरह से इटेटरेटर को गड़बड़ कर देते हैं। इस समस्या से बचने का एक आसान तरीका एक सूची में क्वेरी के परिणामों को "भौतिक" बनाना है, और फिर आप सूची के माध्यम से पुनरावृत्त कर सकते हैं, और इच्छानुसार नोड्स को हटा सकते हैं। निम्नलिखित कोड में एकमात्र अंतर यह है कि यह descendants अक्ष को कॉल करने के बाद ToList को कॉल करता है।

MainDocumentPart mainpart = doc.MainDocumentPart; 
IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants().ToList(); 

foreach(OpenXmlElement elem in elems){ 
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##") 
    { 
     Run run = (Run)elem.Parent; 
     Paragraph p = (Paragraph)run.Parent; 
     p.RemoveAllChildren(); 
     p.Remove(); 
    } 
} 

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

तुम सच में पाठ स्तर पर काम करने के लिए चाहते हैं, तो आप इस तरह के मैं क्या इस स्क्रीन-कलाकारों में परिचय के रूप में कोड का उपयोग करने की जरूरत है: http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/04/introducing-textreplacer-a-new-class-for-powertools-for-open-xml.aspx

वास्तव में, आप शायद उस कोड को संभालने के लिए शब्दशः इस्तेमाल कर सकते हैं अपने मामले का प्रयोग करें, मुझे विश्वास है।

एक और दृष्टिकोण, और अधिक लचीला और शक्तिशाली है, में विस्तृत है:

http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/06/13/open-xml-presentation-generation-using-a-template-presentation.aspx

है कि स्क्रीन कास्ट PresentationML के बारे में है, इसी सिद्धांत WordprocessingML पर लागू होते हैं।

लेकिन यह भी बेहतर है कि आप WordprocessingML का उपयोग कर रहे हैं, सामग्री नियंत्रण का उपयोग करना है।एक दृष्टिकोण पीढ़ी दस्तावेज़ के लिए के लिए देखें:

http://ericwhite.com/blog/map/generating-open-xml-wordprocessingml-documents-blog-post-series/

और सामान्य रूप में सामग्री नियंत्रण का उपयोग के बारे में जानकारी के बहुत सारे के लिए, देखें:

http://www.ericwhite.com/blog/content-controls-expanded

-Eric

+0

असल में मैंने किया है। ToList(), क्योंकि कुछ अन्य जटिलताओं का उपयोग पिछले उपाय। साथ ही, मुझे कई रनों में विभाजित शब्द के बारे में पता है (यह, यहां, बुरा उदाहरण था), इसलिए मेरे प्लेसहोल्डर के पास '_' नहीं है। और मेरे प्लेसहोल्डर हार्डकोड किए गए हैं, इसलिए हालांकि मुझे कंटेंट कंट्रोल फायदे के बारे में पता है, मैंने उनका उपयोग नहीं किया क्योंकि मैं उन्हें काफी अच्छी तरह से नहीं जानता और छोटा (मिनी-) प्रोजेक्ट शेड्यूल करता हूं। उत्तर के लिए धन्यवाद, यह बहुत अंतर्दृष्टिपूर्ण था, और अधिक पूर्ण। –

1

आपको पहले दो चक्रों का उपयोग करना होगा जो उन वस्तुओं को संग्रहीत करते हैं जिन्हें आप हटाना चाहते हैं और दूसरा जो आइटम हटा देता है। कुछ इस तरह:

List<Paragraph> paragraphsToDelete = new List<Paragraph>(); 
foreach(OpenXmlElement elem in elems){ 
    if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##") 
    { 
     Run run = (Run)elem.Parent; 
     Paragraph p = (Paragraph)run.Parent; 
     paragraphsToDelete.Add(p); 
    } 
} 

foreach (var p in paragraphsToDelete) 
{ 
     p.RemoveAllChildren(); 
     p.Remove(); 
} 
+1

भगवान , मैं मूर्ख हूँ। धन्यवाद। लेकिन यह पहली जगह में लूप से क्यों टूटता है? (अगर कोई जानता है, तो मैं इसे उत्तर स्वीकार करने के लिए कुछ समय छोड़ दूंगा; श्री वोट नहीं दे सकते, बहुत कम प्रतिनिधि) –

+0

http://stackoverflow.com/questions/2545027/exception-during-iteration-on-collection-and- हटाएं-आइटम-से-संग्रह-संग्रह –

+0

धन्यवाद। एक और अच्छा मिला: http://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute –

0
Dim elems As IEnumerable(Of OpenXmlElement) = MainPart.Document.Body.Descendants().ToList() 
     For Each elem As OpenXmlElement In elems 
      If elem.InnerText.IndexOf("fullname") > 0 Then 
       elem.RemoveAllChildren() 
      End If 

     Next 

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

  • कोई संबंधित समस्या नहीं^_^