如何使用C#从XML中删除所有命名空间?

我正在寻找干净,优雅和聪明的解决scheme来从所有XML元素中删除命名空间? function如何做到这一点?

界面定义:

public interface IXMLUtils { string RemoveAllNamespaces(string xmlDocument); } 

使用XML从NS中删除NS

 <?xml version="1.0" encoding="utf-16"?> <ArrayOfInserts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <insert> <offer xmlns="http://schema.peters.com/doc_353/1/Types">0174587</offer> <type2 xmlns="http://schema.peters.com/doc_353/1/Types">014717</type2> <supplier xmlns="http://schema.peters.com/doc_353/1/Types">019172</supplier> <id_frame xmlns="http://schema.peters.com/doc_353/1/Types" /> <type3 xmlns="http://schema.peters.com/doc_353/1/Types"> <type2 /> <main>false</main> </type3> <status xmlns="http://schema.peters.com/doc_353/1/Types">Some state</status> </insert> </ArrayOfInserts> 

在我们调用RemoveAllNamespaces(xmlWithLotOfNs)之后,我们应该得到:

  <?xml version="1.0" encoding="utf-16"?> <ArrayOfInserts> <insert> <offer >0174587</offer> <type2 >014717</type2> <supplier >019172</supplier> <id_frame /> <type3 > <type2 /> <main>false</main> </type3> <status >Some state</status> </insert> </ArrayOfInserts> 

解决scheme的首选语言是.NET 3.5 SP1上的C#。

那么,这是最后的答案。 我已经使用了很棒的Jimmy的想法(不幸的是它本身并不完整),并完成recursionfunction正常工作。

基于界面:

 string RemoveAllNamespaces(string xmlDocument); 

我在这里表示最终清除和通用的C#解决scheme,用于删除XML名称空间:

 //Implemented based on interface, not part of algorithm public static string RemoveAllNamespaces(string xmlDocument) { XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument)); return xmlDocumentWithoutNs.ToString(); } //Core recursion function private static XElement RemoveAllNamespaces(XElement xmlDocument) { if (!xmlDocument.HasElements) { XElement xElement = new XElement(xmlDocument.Name.LocalName); xElement.Value = xmlDocument.Value; foreach (XAttribute attribute in xmlDocument.Attributes()) xElement.Add(attribute); return xElement; } return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el))); } 

这是100%的工作,但我没有太多的testing,所以它可能不包括一些特殊情况…但它是一个很好的基础开始。

标记最有用的答案有两个缺陷:

  • 它忽略了属性
  • 它不适用于“混合模式”元素

这是我的承担:

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

示例代码在这里 。

使用LINQ的强制性答案:

 static XElement stripNS(XElement root) { return new XElement( root.Name.LocalName, root.HasElements ? root.Elements().Select(el => stripNS(el)) : (object)root.Value ); } static void Main() { var xml = XElement.Parse(@"<?xml version=""1.0"" encoding=""utf-16""?> <ArrayOfInserts xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> <insert> <offer xmlns=""http://schema.peters.com/doc_353/1/Types"">0174587</offer> <type2 xmlns=""http://schema.peters.com/doc_353/1/Types"">014717</type2> <supplier xmlns=""http://schema.peters.com/doc_353/1/Types"">019172</supplier> <id_frame xmlns=""http://schema.peters.com/doc_353/1/Types"" /> <type3 xmlns=""http://schema.peters.com/doc_353/1/Types""> <type2 /> <main>false</main> </type3> <status xmlns=""http://schema.peters.com/doc_353/1/Types"">Some state</status> </insert> </ArrayOfInserts>"); Console.WriteLine(stripNS(xml)); } 

这将做的伎俩:-)

 foreach (XElement XE in Xml.DescendantsAndSelf()) { // Stripping the namespace by setting the name of the element to it's localname only XE.Name = XE.Name.LocalName; // replacing all attributes with attributes that are not namespaces and their names are set to only the localname XE.ReplaceAttributes((from xattrib in XE.Attributes().Where(xa => !xa.IsNamespaceDeclaration) select new XAttribute(xattrib.Name.LocalName, xattrib.Value))); } 

再捡起来,在C#中添加行来复制属性:

  static XElement stripNS(XElement root) { XElement res = new XElement( root.Name.LocalName, root.HasElements ? root.Elements().Select(el => stripNS(el)) : (object)root.Value ); res.ReplaceAttributes( root.Attributes().Where(attr => (!attr.IsNamespaceDeclaration))); return res; } 

使用XSLT的强制性答案:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no" encoding="UTF-8"/> <xsl:template match="/|comment()|processing-instruction()"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="*"> <xsl:element name="{local-name()}"> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> <xsl:template match="@*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> </xsl:stylesheet> 

我知道这个问题据说已经解决了,但是我对它的实施方式并不满意。 我在MSDN博客上发现了另外一个源代码,它有一个重写的XmlTextWriterXmlTextWriter命名空间。 我调整了一下,得到了一些我想要的东西,比如格式漂亮,保存了根元素。 这是我目前在我的项目中所拥有的。

http://blogs.msdn.com/b/kaevans/archive/2004/08/02/206432.aspx

 /// <summary> /// Modified XML writer that writes (almost) no namespaces out with pretty formatting /// </summary> /// <seealso cref="http://blogs.msdn.com/b/kaevans/archive/2004/08/02/206432.aspx"/> public class XmlNoNamespaceWriter : XmlTextWriter { private bool _SkipAttribute = false; private int _EncounteredNamespaceCount = 0; public XmlNoNamespaceWriter(TextWriter writer) : base(writer) { this.Formatting = System.Xml.Formatting.Indented; } public override void WriteStartElement(string prefix, string localName, string ns) { base.WriteStartElement(null, localName, null); } public override void WriteStartAttribute(string prefix, string localName, string ns) { //If the prefix or localname are "xmlns", don't write it. //HOWEVER... if the 1st element (root?) has a namespace we will write it. if ((prefix.CompareTo("xmlns") == 0 || localName.CompareTo("xmlns") == 0) && _EncounteredNamespaceCount++ > 0) { _SkipAttribute = true; } else { base.WriteStartAttribute(null, localName, null); } } public override void WriteString(string text) { //If we are writing an attribute, the text for the xmlns //or xmlns:prefix declaration would occur here. Skip //it if this is the case. if (!_SkipAttribute) { base.WriteString(text); } } public override void WriteEndAttribute() { //If we skipped the WriteStartAttribute call, we have to //skip the WriteEndAttribute call as well or else the XmlWriter //will have an invalid state. if (!_SkipAttribute) { base.WriteEndAttribute(); } //reset the boolean for the next attribute. _SkipAttribute = false; } public override void WriteQualifiedName(string localName, string ns) { //Always write the qualified name using only the //localname. base.WriteQualifiedName(localName, null); } } 

用法

 //Save the updated document using our modified (almost) no-namespace XML writer using(StreamWriter sw = new StreamWriter(this.XmlDocumentPath)) using(XmlNoNamespaceWriter xw = new XmlNoNamespaceWriter(sw)) { //This variable is of type `XmlDocument` this.XmlDocumentRoot.Save(xw); } 

这是一个基于Peter Stegnar接受的答案的解决scheme。

我用它,但是(正如andygjp和John Saunders所说)他的代码忽略了属性

我也需要照顾属性,所以我改编了他的代码。 安迪的版本是Visual Basic,这仍然是C#。

我知道这已经有一段时间了,但也许有一天有时候会有人救人。

  private static XElement RemoveAllNamespaces(XElement xmlDocument) { XElement xmlDocumentWithoutNs = removeAllNamespaces(xmlDocument); return xmlDocumentWithoutNs; } private static XElement removeAllNamespaces(XElement xmlDocument) { var stripped = new XElement(xmlDocument.Name.LocalName); foreach (var attribute in xmlDocument.Attributes().Where( attribute => !attribute.IsNamespaceDeclaration && String.IsNullOrEmpty(attribute.Name.NamespaceName))) { stripped.Add(new XAttribute(attribute.Name.LocalName, attribute.Value)); } if (!xmlDocument.HasElements) { stripped.Value = xmlDocument.Value; return stripped; } stripped.Add(xmlDocument.Elements().Select( el => RemoveAllNamespaces(el))); return stripped; } 

这是一个完美的解决scheme,也将删除XSI元素。 (如果你删除xmlns,不要删除XSI,.Net在你的留言…)

 string xml = node.OuterXml; //Regex below finds strings that start with xmlns, may or may not have :and some text, then continue with = //and ", have a streach of text that does not contain quotes and end with ". similar, will happen to an attribute // that starts with xsi. string strXMLPattern = @"xmlns(:\w+)?=""([^""]+)""|xsi(:\w+)?=""([^""]+)"""; xml = Regex.Replace(xml, strXMLPattern, ""); 

稍微修改彼得的答案,这也适用于该属性,包括删除命名空间和前缀。 有点抱歉的代码看起来有点难看。

  private static XElement RemoveAllNamespaces(XElement xmlDocument) { if (!xmlDocument.HasElements) { XElement xElement = new XElement(xmlDocument.Name.LocalName); xElement.Value = xmlDocument.Value; foreach (XAttribute attribute in xmlDocument.Attributes()) { xElement.Add(new XAttribute(attribute.Name.LocalName, attribute.Value)); } return xElement; } else { XElement xElement = new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el))); foreach (XAttribute attribute in xmlDocument.Attributes()) { xElement.Add(new XAttribute(attribute.Name.LocalName, attribute.Value)); } return xElement; } } 

你可以使用Linq来做到这一点:

 public static string RemoveAllNamespaces(string xmlDocument) { var xml = XElement.Parse(xmlDocument); xml.Descendants().Select(o => o.Name = o.Name.LocalName).ToArray(); return xml.ToString(); } 

我真的很喜欢德克斯特在那里,所以我把它翻译成一个“stream利的”扩展方法:

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

“stream利”的做法,让我这样做:

 var xml = File.ReadAllText(presentationFile); var xDoc = XDocument.Parse(xml); var xRoot = xDoc.Root.WithoutNamespaces(); 

吉米和彼得的回复非常有帮助,但是他们实际上删除了所有的属性,所以我做了一个小小的修改:

 Imports System.Runtime.CompilerServices Friend Module XElementExtensions <Extension()> _ Public Function RemoveAllNamespaces(ByVal element As XElement) As XElement If element.HasElements Then Dim cleanElement = RemoveAllNamespaces(New XElement(element.Name.LocalName, element.Attributes)) cleanElement.Add(element.Elements.Select(Function(el) RemoveAllNamespaces(el))) Return cleanElement Else Dim allAttributesExceptNamespaces = element.Attributes.Where(Function(attr) Not attr.IsNamespaceDeclaration) element.ReplaceAttributes(allAttributesExceptNamespaces) Return element End If End Function End Module 

对于属性的工作for循环添加属性应recursion后,还需要检查是否IsNamespaceDeclaration:

 private static XElement RemoveAllNamespaces(XElement xmlDocument) { XElement xElement; if (!xmlDocument.HasElements) { xElement = new XElement(xmlDocument.Name.LocalName) { Value = xmlDocument.Value }; } else { xElement = new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(RemoveAllNamespaces)); } foreach (var attribute in xmlDocument.Attributes()) { if (!attribute.IsNamespaceDeclaration) { xElement.Add(attribute); } } return xElement; } 

这里是我的VB.NET版本的德克斯特Legaspi C#版本

 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 

考虑可能交错TEXT和ELEMENT节点的另一种解决scheme,例如:

 <parent> text1 <child1/> text2 <child2/> </parent> 

码:

 using System.Linq; namespace System.Xml.Linq { public static class XElementTransformExtensions { public static XElement WithoutNamespaces(this XElement source) { return new XElement(source.Name.LocalName, source.Attributes().Select(WithoutNamespaces), source.Nodes().Select(WithoutNamespaces) ); } public static XAttribute WithoutNamespaces(this XAttribute source) { return !source.IsNamespaceDeclaration ? new XAttribute(source.Name.LocalName, source.Value) : default(XAttribute); } public static XNode WithoutNamespaces(this XNode source) { return source is XElement ? WithoutNamespaces((XElement)source) : source; } } } 

如果你不想使用基于XSLT的解决scheme,如果你想要干净,优雅和聪明,你需要来自框架的一些支持,特别是访问者模式可以使这一点变得轻而易举。 不幸的是,这里不可用。

我已经通过LINQ的ExpressionVisitor实现了它,它具有类似的结构。 有了这个,你可以将访问者模式应用到(LINQ-to-to-XML)对象。 (我已经做了有限的testing,但是据我所知,效果很好)

 public abstract class XObjectVisitor { public virtual XObject Visit(XObject node) { if (node != null) return node.Accept(this); return node; } public ReadOnlyCollection<XObject> Visit(IEnumerable<XObject> nodes) { return nodes.Select(node => Visit(node)) .Where(node => node != null) .ToList() .AsReadOnly(); } public T VisitAndConvert<T>(T node) where T : XObject { if (node != null) return Visit(node) as T; return node; } public ReadOnlyCollection<T> VisitAndConvert<T>(IEnumerable<T> nodes) where T : XObject { return nodes.Select(node => VisitAndConvert(node)) .Where(node => node != null) .ToList() .AsReadOnly(); } protected virtual XObject VisitAttribute(XAttribute node) { return node.Update(node.Name, node.Value); } protected virtual XObject VisitComment(XComment node) { return node.Update(node.Value); } protected virtual XObject VisitDocument(XDocument node) { return node.Update( node.Declaration, VisitAndConvert(node.Nodes()) ); } protected virtual XObject VisitElement(XElement node) { return node.Update( node.Name, VisitAndConvert(node.Attributes()), VisitAndConvert(node.Nodes()) ); } protected virtual XObject VisitDocumentType(XDocumentType node) { return node.Update( node.Name, node.PublicId, node.SystemId, node.InternalSubset ); } protected virtual XObject VisitProcessingInstruction(XProcessingInstruction node) { return node.Update( node.Target, node.Data ); } protected virtual XObject VisitText(XText node) { return node.Update(node.Value); } protected virtual XObject VisitCData(XCData node) { return node.Update(node.Value); } #region Implementation details internal InternalAccessor Accessor { get { return new InternalAccessor(this); } } internal class InternalAccessor { private XObjectVisitor visitor; internal InternalAccessor(XObjectVisitor visitor) { this.visitor = visitor; } internal XObject VisitAttribute(XAttribute node) { return visitor.VisitAttribute(node); } internal XObject VisitComment(XComment node) { return visitor.VisitComment(node); } internal XObject VisitDocument(XDocument node) { return visitor.VisitDocument(node); } internal XObject VisitElement(XElement node) { return visitor.VisitElement(node); } internal XObject VisitDocumentType(XDocumentType node) { return visitor.VisitDocumentType(node); } internal XObject VisitProcessingInstruction(XProcessingInstruction node) { return visitor.VisitProcessingInstruction(node); } internal XObject VisitText(XText node) { return visitor.VisitText(node); } internal XObject VisitCData(XCData node) { return visitor.VisitCData(node); } } #endregion } public static class XObjectVisitorExtensions { #region XObject.Accept "instance" method public static XObject Accept(this XObject node, XObjectVisitor visitor) { Validation.CheckNullReference(node); Validation.CheckArgumentNull(visitor, "visitor"); // yay, easy dynamic dispatch Acceptor acceptor = new Acceptor(node as dynamic); return acceptor.Accept(visitor); } private class Acceptor { public Acceptor(XAttribute node) : this(v => v.Accessor.VisitAttribute(node)) { } public Acceptor(XComment node) : this(v => v.Accessor.VisitComment(node)) { } public Acceptor(XDocument node) : this(v => v.Accessor.VisitDocument(node)) { } public Acceptor(XElement node) : this(v => v.Accessor.VisitElement(node)) { } public Acceptor(XDocumentType node) : this(v => v.Accessor.VisitDocumentType(node)) { } public Acceptor(XProcessingInstruction node) : this(v => v.Accessor.VisitProcessingInstruction(node)) { } public Acceptor(XText node) : this(v => v.Accessor.VisitText(node)) { } public Acceptor(XCData node) : this(v => v.Accessor.VisitCData(node)) { } private Func<XObjectVisitor, XObject> accept; private Acceptor(Func<XObjectVisitor, XObject> accept) { this.accept = accept; } public XObject Accept(XObjectVisitor visitor) { return accept(visitor); } } #endregion #region XObject.Update "instance" method public static XObject Update(this XAttribute node, XName name, string value) { Validation.CheckNullReference(node); Validation.CheckArgumentNull(name, "name"); Validation.CheckArgumentNull(value, "value"); return new XAttribute(name, value); } public static XObject Update(this XComment node, string value = null) { Validation.CheckNullReference(node); return new XComment(value); } public static XObject Update(this XDocument node, XDeclaration declaration = null, params object[] content) { Validation.CheckNullReference(node); return new XDocument(declaration, content); } public static XObject Update(this XElement node, XName name, params object[] content) { Validation.CheckNullReference(node); Validation.CheckArgumentNull(name, "name"); return new XElement(name, content); } public static XObject Update(this XDocumentType node, string name, string publicId = null, string systemId = null, string internalSubset = null) { Validation.CheckNullReference(node); Validation.CheckArgumentNull(name, "name"); return new XDocumentType(name, publicId, systemId, internalSubset); } public static XObject Update(this XProcessingInstruction node, string target, string data) { Validation.CheckNullReference(node); Validation.CheckArgumentNull(target, "target"); Validation.CheckArgumentNull(data, "data"); return new XProcessingInstruction(target, data); } public static XObject Update(this XText node, string value = null) { Validation.CheckNullReference(node); return new XText(value); } public static XObject Update(this XCData node, string value = null) { Validation.CheckNullReference(node); return new XCData(value); } #endregion } public static class Validation { public static void CheckNullReference<T>(T obj) where T : class { if (obj == null) throw new NullReferenceException(); } public static void CheckArgumentNull<T>(T obj, string paramName) where T : class { if (obj == null) throw new ArgumentNullException(paramName); } } 

ps,这个特定的实现使用了一些.NET 4的特性来使实现变得简单一些(使用dynamic参数和默认参数)。 使.NET 3.5兼容,甚至可能与.NET 2.0兼容,不应该太困难。

然后为了实现访问者,这是一个可以改变多个名字空间(和使用的前缀)的通用化的访问器。

 public class ChangeNamespaceVisitor : XObjectVisitor { private INamespaceMappingManager manager; public ChangeNamespaceVisitor(INamespaceMappingManager manager) { Validation.CheckArgumentNull(manager, "manager"); this.manager = manager; } protected INamespaceMappingManager Manager { get { return manager; } } private XName ChangeNamespace(XName name) { var mapping = Manager.GetMapping(name.Namespace); return mapping.ChangeNamespace(name); } private XObject ChangeNamespaceDeclaration(XAttribute node) { var mapping = Manager.GetMapping(node.Value); return mapping.ChangeNamespaceDeclaration(node); } protected override XObject VisitAttribute(XAttribute node) { if (node.IsNamespaceDeclaration) return ChangeNamespaceDeclaration(node); return node.Update(ChangeNamespace(node.Name), node.Value); } protected override XObject VisitElement(XElement node) { return node.Update( ChangeNamespace(node.Name), VisitAndConvert(node.Attributes()), VisitAndConvert(node.Nodes()) ); } } // and all the gory implementation details public class NamespaceMappingManager : INamespaceMappingManager { private Dictionary<XNamespace, INamespaceMapping> namespaces = new Dictionary<XNamespace, INamespaceMapping>(); public NamespaceMappingManager Add(XNamespace fromNs, XNamespace toNs, string toPrefix = null) { var item = new NamespaceMapping(fromNs, toNs, toPrefix); namespaces.Add(item.FromNs, item); return this; } public INamespaceMapping GetMapping(XNamespace fromNs) { INamespaceMapping mapping; if (!namespaces.TryGetValue(fromNs, out mapping)) mapping = new NullMapping(); return mapping; } private class NullMapping : INamespaceMapping { public XName ChangeNamespace(XName name) { return name; } public XObject ChangeNamespaceDeclaration(XAttribute node) { return node.Update(node.Name, node.Value); } } private class NamespaceMapping : INamespaceMapping { private XNamespace fromNs; private XNamespace toNs; private string toPrefix; public NamespaceMapping(XNamespace fromNs, XNamespace toNs, string toPrefix = null) { this.fromNs = fromNs ?? ""; this.toNs = toNs ?? ""; this.toPrefix = toPrefix; } public XNamespace FromNs { get { return fromNs; } } public XNamespace ToNs { get { return toNs; } } public string ToPrefix { get { return toPrefix; } } public XName ChangeNamespace(XName name) { return name.Namespace == fromNs ? toNs + name.LocalName : name; } public XObject ChangeNamespaceDeclaration(XAttribute node) { if (node.Value == fromNs.NamespaceName) { if (toNs == XNamespace.None) return null; var xmlns = !String.IsNullOrWhiteSpace(toPrefix) ? (XNamespace.Xmlns + toPrefix) : node.Name; return node.Update(xmlns, toNs.NamespaceName); } return node.Update(node.Name, node.Value); } } } public interface INamespaceMappingManager { INamespaceMapping GetMapping(XNamespace fromNs); } public interface INamespaceMapping { XName ChangeNamespace(XName name); XObject ChangeNamespaceDeclaration(XAttribute node); } 

还有一个帮助球的方法:

 T ChangeNamespace<T>(T node, XNamespace fromNs, XNamespace toNs, string toPrefix = null) where T : XObject { return node.Accept( new ChangeNamespaceVisitor( new NamespaceMappingManager() .Add(fromNs, toNs, toPrefix) ) ) as T; } 

然后删除一个命名空间,你可以这样调用它:

 var doc = ChangeNamespace(XDocument.Load(pathToXml), fromNs: "http://schema.peters.com/doc_353/1/Types", toNs: null); 

使用这个访问者,你可以编写一个INamespaceMappingManager去除所有的命名空间。

 T RemoveAllNamespaces<T>(T node) where T : XObject { return node.Accept( new ChangeNamespaceVisitor(new RemoveNamespaceMappingManager()) ) as T; } public class RemoveNamespaceMappingManager : INamespaceMappingManager { public INamespaceMapping GetMapping(XNamespace fromNs) { return new RemoveNamespaceMapping(); } private class RemoveNamespaceMapping : INamespaceMapping { public XName ChangeNamespace(XName name) { return name.LocalName; } public XObject ChangeNamespaceDeclaration(XAttribute node) { return null; } } } 

简单的解决scheme,实际上重命名的元素,而不是创build一个副本,并做了很好的replace属性。

 public void RemoveAllNamespaces(ref XElement value) { List<XAttribute> attributesToRemove = new List<XAttribute>(); foreach (void e_loopVariable in value.DescendantsAndSelf) { e = e_loopVariable; if (e.Name.Namespace != XNamespace.None) { e.Name = e.Name.LocalName; } foreach (void a_loopVariable in e.Attributes) { a = a_loopVariable; if (a.IsNamespaceDeclaration) { //do not keep it at all attributesToRemove.Add(a); } else if (a.Name.Namespace != XNamespace.None) { e.SetAttributeValue(a.Name.LocalName, a.Value); attributesToRemove.Add(a); } } } foreach (void a_loopVariable in attributesToRemove) { a = a_loopVariable; a.Remove(); } } 

注意:这并不总是保留原来的属性顺序,但我相信如果对你很重要的话,你可以改变它来做到这一点。

另外请注意,如果您有一个XElement属性只与名称空间相同,那么这也可能会引发exception:

 <root xmlns:ns1="a" xmlns:ns2="b"> <elem ns1:dupAttrib="" ns2:dupAttrib="" /> </root> 

这真的是一个固有的问题。 但由于问题指出输出一个string,而不是一个XElement,在这种情况下,你可以有一个解决scheme,将输出一个有效的string是一个无效的XElement。

我也喜欢使用自定义的XmlWriter的jocull的答案,但是当我尝试它,它不适合我。 虽然这一切看起来都是正确的,但我无法判断XmlNoNamespaceWriter类是否完全有效; 它绝对不是删除命名空间,因为我想要的。

添加我也清除了名称空间前缀的节点的名称:

  public static string RemoveAllNamespaces(XElement element) { string tex = element.ToString(); var nsitems = element.DescendantsAndSelf().Select(n => n.ToString().Split(' ', '>')[0].Split('<')[1]).Where(n => n.Contains(":")).DistinctBy(n => n).ToArray(); //Namespace prefix on nodes: <a:nodename/> tex = nsitems.Aggregate(tex, (current, nsnode) => current.Replace("<"+nsnode + "", "<" + nsnode.Split(':')[1] + "")); tex = nsitems.Aggregate(tex, (current, nsnode) => current.Replace("</" + nsnode + "", "</" + nsnode.Split(':')[1] + "")); //Namespace attribs var items = element.DescendantsAndSelf().SelectMany(d => d.Attributes().Where(a => a.IsNamespaceDeclaration || a.ToString().Contains(":"))).DistinctBy(o => o.Value); tex = items.Aggregate(tex, (current, xAttribute) => current.Replace(xAttribute.ToString(), "")); return tex; } 

I tried the first few solutions and didn't work for me. Mainly the problem with attributes being removed like the other have already mentioned. I would say my approach is very similar to Jimmy by using the XElement constructors that taking object as parameters.

 public static XElement RemoveAllNamespaces(this XElement element) { return new XElement(element.Name.LocalName, element.HasAttributes ? element.Attributes().Select(a => new XAttribute(a.Name.LocalName, a.Value)) : null, element.HasElements ? element.Elements().Select(e => RemoveAllNamespaces(e)) : null, element.Value); } 

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

user892217's answer is almost correct. It won't compile as is, so needs a slight correction to the recursive call:

 private static XElement RemoveAllNamespaces(XElement xmlDocument) { XElement xElement; if (!xmlDocument.HasElements) { xElement = new XElement(xmlDocument.Name.LocalName) { Value = xmlDocument.Value }; } else { xElement = new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(x => RemoveAllNamespaces(x))); } foreach (var attribute in xmlDocument.Attributes()) { if (!attribute.IsNamespaceDeclaration) { xElement.Add(attribute); } } return xElement; } 

这对我有效。

  FileStream fs = new FileStream(filePath, FileMode.Open); StreamReader sr = new StreamReader(fs); DataSet ds = new DataSet(); ds.ReadXml(sr); ds.Namespace = ""; string outXML = ds.GetXml(); ds.Dispose(); sr.Dispose(); fs.Dispose(); 

After much searching for a solution to this very issue, this particular page seemed to have the most beef…however, nothing quite fit exactly, so I took the old-fashioned way and just parsed the stuff out I wanted out. 希望这有助于某人。 (Note: this also removes the SOAP or similar envelope stuff.)

  public static string RemoveNamespaces(string psXml) { // // parse through the passed XML, and remove any and all namespace references...also // removes soap envelope/header(s)/body, or any other references via ":" entities, // leaving all data intact // string xsXml = "", xsCurrQtChr = ""; int xiPos = 0, xiLastPos = psXml.Length - 1; bool xbInNode = false; while (xiPos <= xiLastPos) { string xsCurrChr = psXml.Substring(xiPos, 1); xiPos++; if (xbInNode) { if (xsCurrChr == ":") { // soap envelope or body (or some such) // we'll strip these node wrappers completely // need to first strip the beginning of it off (ie "<soap" or "<s") int xi = xsXml.Length; string xsChr = ""; do { xi--; xsChr = xsXml.Substring(xi, 1); xsXml = xsXml.Substring(0, xi); } while (xsChr != "<"); // next, find end of node string xsQt = ""; do { xiPos++; if (xiPos <= xiLastPos) { xsChr = psXml.Substring(xiPos, 1); if (xsQt.Length == 0) { if (xsChr == "'" || xsChr == "\"") { xsQt = xsChr; } } else { if (xsChr == xsQt) { xsQt = ""; // end of quote } else { if (xsChr == ">") xsChr = "x"; // stay in loop...this is not end of node } } } } while (xsChr != ">" && xiPos <= xiLastPos); xiPos++; // skip over closing ">" xbInNode = false; } else { if (xsCurrChr == ">") { xbInNode = false; xsXml += xsCurrChr; } else { if (xsCurrChr == " " || xsCurrChr == "\t") { // potential namespace...let's check...next character must be "/" // or more white space, and if not, skip until we find such string xsChr = ""; int xiOrgLen = xsXml.Length; xsXml += xsCurrChr; do { if (xiPos <= xiLastPos) { xsChr = psXml.Substring(xiPos, 1); xiPos++; if (xsChr == " " || xsChr == "\r" || xsChr == "\n" || xsChr == "\t") { // carry on..white space xsXml += xsChr; } else { if (xsChr == "/" || xsChr == ">") { xsXml += xsChr; } else { // namespace! - get rid of it xsXml = xsXml.Substring(0, xiOrgLen - 0); // first, truncate any added whitespace // next, peek forward until we find "/" or ">" string xsQt = ""; do { if (xiPos <= xiLastPos) { xsChr = psXml.Substring(xiPos, 1); xiPos++; if (xsQt.Length > 0) { if (xsChr == xsQt) xsQt = ""; else xsChr = "x"; } else { if (xsChr == "'" || xsChr == "\"") xsQt = xsChr; } } } while (xsChr != ">" && xsChr != "/" && xiPos <= xiLastPos); if (xsChr == ">" || xsChr == "/") xsXml += xsChr; xbInNode = false; } } } } while (xsChr != ">" && xsChr != "/" && xiPos <= xiLastPos); } else { xsXml += xsCurrChr; } } } } else { // // if not currently inside a node, then we are in a value (or about to enter a new node) // xsXml += xsCurrChr; if (xsCurrQtChr.Length == 0) { if (xsCurrChr == "<") { xbInNode = true; } } else { // // currently inside a quoted string // if (xsCurrQtChr == xsCurrChr) { // finishing quoted string xsCurrQtChr = ""; } } } } return (xsXml); } 

Here's are Regex Replace one liner:

 public static string RemoveNamespaces(this string xml) { return Regex.Replace(xml, "((?<=<|<\\/)|(?<= ))[A-Za-z0-9]+:| xmlns(:[A-Za-z0-9]+)?=\".*?\"", ""); } 

Here's a sample: https://regex101.com/r/fopydN/6

Warning:there might be edge cases!

Without recreating whole node hierarchy:

 private static void RemoveDefNamespace(XElement element) { var defNamespase = element.Attribute("xmlns"); if (defNamespase != null) defNamespase.Remove(); element.Name = element.Name.LocalName; foreach (var child in element.Elements()) { RemoveDefNamespace(child); } } 

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 )

Here is a regex based solution to this problem…

  private XmlDocument RemoveNS(XmlDocument doc) { var xml = doc.OuterXml; var newxml = Regex.Replace(xml, @"xmlns[:xsi|:xsd]*="".*?""",""); var newdoc = new XmlDocument(); newdoc.LoadXml(newxml); return newdoc; } 

I think this is shortest answer(but for constuctions like , you will have another discussion, I also have regex to convert "<bcm:info></bcm:info>" to " <info></info> " but it wasn't optimized, If someone ask me I will share it. So, my solution is:

  public string RemoveAllNamespaces(string xmlDocument) { return Regex.Replace(xmlDocument, @"\sxmlns(\u003A\w+)?\u003D\u0022.+\u0022", " "); }