Linq-to-XML XElement.Remove () оставляет нежелательные пробелы

У меня есть XDocument, который я создаю из массива байтов (полученного через tcp / ip).

Затем я ищу определенные узлы xml (XElements)и после получения значения «вытолкните» его из Xdocument, вызвав XElement.Remove (). После того, как весь мой синтаксический анализ завершен, я хочу иметь возможность регистрировать xml, который я не анализировал (оставшийся xml в XDocument). Проблема в том, что при вызове XElement.Remove () остается лишний пробел. Я хочу узнать, как лучше всего удалить этот лишний пробел, сохранив остальную часть формата в оставшемся xml.

Пример / образец кода

Если я получаю следующий 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, отправляемая в сообщение LogUnparsedXML, будет иметь вид:

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

В этом надуманном примере это может показаться неважным, но мое фактическое приложение, оставшийся xml выглядит довольно неаккуратно. Я попытался использовать перегрузку XDocument.ToString, которая безрезультатно использует перечисление SaveOptions. Я также попытался вызвать xDoc.Save для сохранения в файл с помощью перечисления SaveOptions. Я попытался поэкспериментировать с несколькими разными запросами linq, которые использовали XElement.Nodes (). OfType () , чтобы попытаться удалить пробелы, но часто в итоге я брал пробелы, которые я хотел сохранить вместе с пробелами, от которых я пытаюсь избавиться.

Заранее благодарю за помощь.

Джо

10
задан Joe DePung 27 July 2011 в 21:05
поделиться

2 ответа

У меня есть простое решение, чем принятый ответ, который работает на мой случай и, кажется, работает на Ваш также. Возможно, существуют некоторые более сложные случаи, это не будет работать на то, хотя, я не уверен.

Вот код:

public static void RemoveWithNextWhitespace(this XElement element)
{
    if (element.PreviousNode is XText textNode)
    {
        textNode.Remove();
    }

    element
    .Remove();
}

Вот мой запрос LINQPad с Вашим вариантом использования:

void Main()
{
    var xDoc = XDocument.Parse(@"<?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>", LoadOptions.PreserveWhitespace);

    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.RemoveWithNextWhitespace();
    if (Title != null) Title.RemoveWithNextWhitespace();
    if (Genre != null) Genre.RemoveWithNextWhitespace();

    xDoc.ToString().Dump();
}

static class Ext
{
    public static void RemoveWithNextWhitespace(this XElement element)
    {
        if (element.PreviousNode is XText textNode)
        {
            textNode.Remove();
        }

        element
        .Remove();
    }
}

главная причина, почему я только не использовал принятый ответ сам, состояла в том, потому что это не оставило мой XML правильно отформатированным в некоторых случаях. например, в Вашем варианте использования, если бы я удалил элемент "описания", он оставил бы что-то, что было похоже на это:

<catalog>
   <book id="bk101">
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
         </book>
</catalog>
0
ответ дан 4 December 2019 в 02:46
поделиться

Чтение xml через XmlReader сохранит пробел по умолчанию, включая незначительный пробел, как Вы видите здесь.

необходимо считать его в игнорировании пробела путем установки соответствующего xml читателя, устанавливающего:

using (var reader = XmlReader.Create(xmlStream, new XmlReaderSettings { IgnoreWhitespace = true }))

Примечание это не удаляет значительный пробел (такой как те, которые в смешанном содержании или в пробеле сохранения объема), таким образом, Ваше форматирование останется.

0
ответ дан 4 December 2019 в 02:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: