2011-07-27 18 views
9

Bayt dizisinden oluşturduğum bir XDocument var (tcp/ip üzerinden alınan).Linq'den XML'e XElement.Remove() istenmeyen boşluk bırakıyor

Ardından, belirli xml düğümlerini (XElements) arar ve XElement öğesinin XElement.Remove() öğesini çağırarak 'pop' değerini almasını sağladıktan sonra. Tüm ayrıştırma tamamlandıktan sonra ayrılmamış xml dosyasını (XDocument içinde kalan xml) günlüğe kaydedebilmek istiyorum. Sorun, XElement.Remove() çağrıldığında kalan fazladan boşluk olmasıdır. Kalan xml'deki formatın geri kalan kısmını korurken bu ekstra boşlukları kaldırmanın en iyi yolunu bilmek istiyorum.

Örnek/Örnek Kod

ben soket üzerinde aşağıdaki xml alırsanız:

<?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> 

Ve bu xml ayrıştırma ve XElements bir dizi kaldırmak için aşağıdaki kodu kullanın:

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... 
    } 
} 

Daha sonra LogUnparsedXML iletisine gönderilen sonuç xml dizesi şu şekilde olur:

<?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> 

Bu kısıtlı örnekte, büyük bir anlaşma gibi görünmeyebilir, ancak gerçek uygulamamda artık xml oldukça belirsiz görünüyor. Ben bir SaveOptions enum alır boş bir XDocument.ToString aşırı yüklemesini kullanmaya çalıştım. Ayrıca SaveOptions enum kullanarak bir dosyaya kaydetmek için xDoc.Save'i aramayı denedim. Ben boşluğu kaldırmak için denemek için XElement.Nodes().OfType<XText>() kullanılan birkaç farklı linq sorguları ile denemeyi deneyin, ama genellikle kurtulmak için çalışıyorum boşluk ile birlikte korumak istediğim boşluk alarak sona erdi.

Yardım için şimdiden teşekkür ederiz.

Joe

+0

'ToString()' çağrısındaki seçenekleri 'SaveOptions.DisableFormatting' olarak ayarlamayı deneyin. –

cevap

3

çözüm ağır XDocument.Load() boşluk metin düğümlerini oluşturur bağlıdır (ve bu ince detay hakkında hemfikir olabilir etrafında XML LINQ çeşitli uygulamaları vardır) çünkü taşınabilir bir şekilde cevap vermek kolay değil .

asla <book> elementlerden son çocuk ( <description>) kaldırarak anlaşıldığından, Söylediğin. Eğer durum böyleyse, ana elemanın kapanış etiketinin girintisi hakkında endişelenmemize gerek kalmaz ve öğeyi ve tüm takip eden metin düğümlerini başka bir elemana ulaşıncaya kadar kaldırabiliriz. TakeWhile() işi yapacak.

DÜZENLEME: Peki, sonuncu çocuğu kaldırmanız gerekiyor. Bu nedenle, işler daha da karmaşıklaşacaktır. Bir sonraki elemanı ulaşana kadar

  • aşağıdaki tüm metin düğümleri kaldırın: eleman son üst biriminin elemanı değilse

    • : Aşağıdaki kod aşağıdaki algoritmayı uygular.
  • Aksi halde: aşağıdaki tüm metin düğümleri bir yeni satır içeren bir buluncaya kadar
    • Kaldır, o düğüm sadece yeni satır içeriyorsa
    • :
      • bu düğümü çıkarın. Aksi
    • :
      • yeni satır sonra bulundu sadece boşluk içeren yeni bir düğüm oluşturma
      • orijinal düğüm sonra bu düğümü yerleştirin
      • orijinal düğümü çıkarın.
  • elemanını kendisi çıkarın.

çıkan kodudur: Oradan

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(); 
} 

, yapabileceğiniz:

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

senin bir beslenen bir döngü gibi bir şeyle yukarıdaki değiştirmek öneririm rağmen kod yedeklemesini önlemek için dizi veya params yöntem çağrısı.

İlgili konular