How to remove all namespaces from XML with C#?

前端 未结 30 2221
悲哀的现实
悲哀的现实 2020-11-22 13:30

I am looking for the clean, elegant and smart solution to remove namespacees from all XML elements? How would function to do that look like?

Defined interface:

相关标签:
30条回答
  • 2020-11-22 13:37

    I really liked where Dexter is going up there so I translated it into a “fluent” extension method:

    /// <summary>
    /// Returns the specified <see cref="XElement"/>
    /// without namespace qualifiers on elements and attributes.
    /// </summary>
    /// <param name="element">The element</param>
    public static XElement WithoutNamespaces(this XElement element)
    {
        if (element == null) return null;
    
        #region delegates:
    
            Func<XNode, XNode> getChildNode = e => (e.NodeType == XmlNodeType.Element) ? (e as XElement).WithoutNamespaces() : e;
    
            Func<XElement, IEnumerable<XAttribute>> getAttributes = e => (e.HasAttributes) ?
                e.Attributes()
                    .Where(a => !a.IsNamespaceDeclaration)
                    .Select(a => new XAttribute(a.Name.LocalName, a.Value))
                :
                Enumerable.Empty<XAttribute>();
    
            #endregion
    
        return new XElement(element.Name.LocalName,
            element.Nodes().Select(getChildNode),
            getAttributes(element));
    }
    

    The “fluent” approach allows me to do this:

    var xml = File.ReadAllText(presentationFile);
    var xDoc = XDocument.Parse(xml);
    var xRoot = xDoc.Root.WithoutNamespaces();
    
    0 讨论(0)
  • 2020-11-22 13:37

    Here is my VB.NET version of Dexter Legaspi C# Version

    Shared Function RemoveAllNamespaces(ByVal e As XElement) As XElement
            Return New XElement(e.Name.LocalName, New Object() {(From n In e.Nodes Select If(TypeOf n Is XElement, RemoveAllNamespaces(TryCast(n, XElement)), n)), If(e.HasAttributes, (From a In e.Attributes Select a), Nothing)})
    End Function
    
    0 讨论(0)
  • 2020-11-22 13:39

    my answer, string-manipulation-based,
    lite-most code,

    public static string hilangkanNamespace(string instrXML)
        {
            char chrOpeningTag = '<';
            char chrClosingTag = '>';
            char chrSpasi = ' ';
            int intStartIndex = 0;
            do
            {
                int intIndexKu = instrXML.IndexOf(chrOpeningTag, intStartIndex);
                if (intIndexKu < 0)
                    break; //kalau dah ga ketemu keluar
                int intStart = instrXML.IndexOfAny(new char[] { chrSpasi, chrClosingTag }, intIndexKu + 1); //mana yang ketemu duluan
                if (intStart < 0)
                    break; //kalau dah ga ketemu keluar
                int intStop = instrXML.IndexOf(chrClosingTag, intStart);
                if (intStop < 0)
                    break; //kalau dah ga ketemu keluar
                else
                    intStop--; //exclude si closingTag
                int intLengthToStrip = intStop - intStart + 1;
                instrXML = instrXML.Remove(intStart, intLengthToStrip);
                intStartIndex = intStart;
            } while (true);
    
            return instrXML;
        }
    
    0 讨论(0)
  • 2020-11-22 13:39

    I tried some of the solutions, but as stated by so many, there are some edge cases.

    Used some of the regexes above, but came to the conclusion that a one step regex is not feasable.

    So here is my solution, 2 step regex, find tags, within tags remove, do not alter cdata:

                Func<Match, String> NamespaceRemover = delegate (Match match)
                {
                    var result = match.Value;
                    if (String.IsNullOrEmpty(match.Groups["cdata"].Value))
                    {
                        // find all prefixes within start-, end tag and attributes and also namespace declarations
                        return Regex.Replace(result, "((?<=<|<\\/| ))\\w+:| xmlns(:\\w+)?=\".*?\"", "");
                    }
                    else
                    {
                        // cdata as is
                        return result;
                    }
                };
                // XmlDocument doc;
                // string file;
                doc.LoadXml(
                  Regex.Replace(File.ReadAllText(file), 
                    // find all begin, cdata and end tags (do not change order)
                    @"<(?:\w+:?\w+.*?|(?<cdata>!\[CDATA\[.*?\]\])|\/\w+:?\w+)>", 
                    new MatchEvaluator(NamespaceRemover)
                  )
                );
    

    For now it is 100% working for me.

    0 讨论(0)
  • 2020-11-22 13:40

    The tagged most useful answer has two flaws:

    • It ignores attributes
    • It doesn't work with "mixed mode" elements

    Here is my take on this:

     public static XElement RemoveAllNamespaces(XElement e)
     {
        return new XElement(e.Name.LocalName,
          (from n in e.Nodes()
            select ((n is XElement) ? RemoveAllNamespaces(n as XElement) : n)),
              (e.HasAttributes) ? 
                (from a in e.Attributes() 
                   where (!a.IsNamespaceDeclaration)  
                   select new XAttribute(a.Name.LocalName, a.Value)) : null);
      }          
    

    Sample code here.

    0 讨论(0)
  • 2020-11-22 13:41

    Bit late to the party on this one but here's what I used recently:

    var doc = XDocument.Parse(xmlString);
    doc.Root.DescendantNodesAndSelf().OfType<XElement>().Attributes().Where(att => att.IsNamespaceDeclaration).Remove();
    

    (taken from this MSDN Thread)

    Edit As per the comment below, it appears that while this removes the namespace prefix from the nodes it doesn't actually remove the xmlns attribute. To do that you need to also reset the name of each node to it's localname (eg name minus namespace)

    foreach (var node in doc.Root.DescendantNodesAndSelf().OfType<XElement>())
    {
        node.Name = node.Name.LocalName;
    }
    
    0 讨论(0)
提交回复
热议问题