Как удалить все дочерние узлы XmlElement, но сохранить все атрибуты?

Как удалить все дочерние узлы XmlElement, но сохранить все атрибуты?

Обратите внимание, что XmlElement.RemoveAll также удаляет все атрибуты. Что такое чистый, элегантный и эффективный способ удаления всех дочерних узлов? Другими словами, что здесь лучше всего?

Ответ 1

Для действительно эффективного решения:

e.IsEmpty = true;

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

Ответ 2

Не будет ли это решение проще?

while(e.FirstChild != null)
    e.RemoveChild(e.FirstChild);

Ответ 3

Вариант 1 Используйте elem.InnerXml = ""; Полный рабочий код, если вам это нужно:

    var doc = new XmlDocument();
    doc.LoadXml("<x a1='a' a2='b'><child1/><child2/></x>");
    var elem = doc.DocumentElement;

    Console.WriteLine(elem.OuterXml);
    Console.WriteLine("HasAttributes " + elem.HasAttributes);
    Console.WriteLine("HasChildNodes " + elem.HasChildNodes);

    elem.InnerXml = "";
    Console.WriteLine(elem.OuterXml);
    Console.WriteLine("HasAttributes " + elem.HasAttributes);
    Console.WriteLine("HasChildNodes " + elem.HasChildNodes);
    Console.ReadLine();

Подробные сведения о том, что делает InnerXml:

    public override string InnerXml
    {
      get
      {
        return base.InnerXml;
      }
      set
      {
        this.RemoveAllChildren();
        new XmlLoader().LoadInnerXmlElement(this, value);
      }
    }

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

internal XmlNamespaceManager ParsePartialContent(XmlNode parentNode, string innerxmltext, XmlNodeType nt)
    {
      this.doc = parentNode.OwnerDocument;
      XmlParserContext context = this.GetContext(parentNode);
      this.reader = this.CreateInnerXmlReader(innerxmltext, nt, context, this.doc);
      try
      {
        this.preserveWhitespace = true;
        bool isLoading = this.doc.IsLoading;
        this.doc.IsLoading = true;
        if (nt == XmlNodeType.Entity)
        {
          XmlNode newChild;
          while (this.reader.Read() && (newChild = this.LoadNodeDirect()) != null)
            parentNode.AppendChildForLoad(newChild, this.doc);
        }
        else
        {
          XmlNode newChild;
          while (this.reader.Read() && (newChild = this.LoadNode(true)) != null)
            parentNode.AppendChildForLoad(newChild, this.doc);
        }
        this.doc.IsLoading = isLoading;
      }
      finally
      {
        this.reader.Close();
      }
      return context.NamespaceManager;
    }

Вариант 2 Следующий код:

    XmlNode todelete = elem.FirstChild;
    while (todelete != null)
    {
        elem.RemoveChild(elem.FirstChild);
        todelete = elem.FirstChild;
    }

О перформансе. Давайте рассмотрим XmlElement.RemoveAll():

public override void RemoveAll()
{
  base.RemoveAll();
  this.RemoveAllAttributes();
}

Где base.RemoveAll():

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public virtual void RemoveAll()
{
  XmlNode oldChild = this.FirstChild;
  for (; oldChild != null; {
    XmlNode nextSibling;
    oldChild = nextSibling;
  }
  )
  {
    nextSibling = oldChild.NextSibling;
    this.RemoveChild(oldChild);
  }
}

Так что, как я писал выше