How to remove all child nodes of an XmlElement, but keep all attributes?

后端 未结 3 385
情话喂你
情话喂你 2021-01-07 23:00

How to remove all child nodes of an XmlElement, but keep all attributes?

Note, that XmlElement.RemoveAll also removes all attributes. What is a clean, e

相关标签:
3条回答
  • 2021-01-07 23:26

    For a truly efficient solution:

    e.IsEmpty = true;
    

    is your fastest and simplest option. It does exactly what you requested: all inner text and nested elements are discarded, while attributes are retained.

    0 讨论(0)
  • 2021-01-07 23:27

    Would this solution not be simpler?

    while(e.FirstChild != null)
        e.RemoveChild(e.FirstChild);
    
    0 讨论(0)
  • 2021-01-07 23:31

    Option 1 Use elem.InnerXml = ""; The full working code if you need this:

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

    Detailied information what InnerXml do:

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

    There could be performance issue on LoadInnerXmlElement but because we have empty string it should not be big, because most time will take this method:

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

    Option 2 Following code:

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

    About performane. Let's look into XmlElement.RemoveAll() it is:

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

    Where base.RemoveAll() is exactly:

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

    So it is same as I wrote above

    0 讨论(0)
提交回复
热议问题