Jak usunąć wszystkie przestrzenie nazw z XML za pomocą C #?

104

Szukam czystego, eleganckiego i inteligentnego rozwiązania do usuwania przestrzeni nazw ze wszystkich elementów XML? Jak by to wyglądało?

Zdefiniowany interfejs:

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

Przykładowy kod XML do usunięcia NS z:

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

Po wywołaniu RemoveAllNamespaces (xmlWithLotOfNs) powinniśmy otrzymać:

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

Preferowanym językiem rozwiązania jest C # na .NET 3.5 SP1.

Peter Stegnar
źródło
@JohnSaunders: Masz rację. Ale w tym konkretnym przypadku muszę przeprowadzić pewną integrację systemu. Wtedy to była jedyna opcja.
Peter Stegnar
@PeterStegnar błąd to zwykle haker, który utworzył starsze formaty. Często programiści często nadużywają XML. Przestrzenie nazw to pierwsza szalenie ważna funkcja, którą należy odrzucić.
Gusdor

Odpowiedzi:

103

Oto ostateczna odpowiedź. Użyłem świetnego pomysłu Jimmy'ego (który niestety nie jest kompletny) i pełnej funkcji rekursji, aby działać poprawnie.

Na podstawie interfejsu:

string RemoveAllNamespaces(string xmlDocument);

Przedstawiam tutaj ostateczne czyste i uniwersalne rozwiązanie C # do usuwania przestrzeni nazw 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)));
    }

Działa w 100%, ale nie testowałem go zbytnio, więc może nie obejmować niektórych specjalnych przypadków ... Ale to dobra podstawa na początek.

Peter Stegnar
źródło
8
Jak dobrze to działa z atrybutami, które mają przestrzenie nazw? W rzeczywistości twój kod po prostu całkowicie ignoruje atrybuty.
John Saunders
6
Zdaję sobie sprawę, że przestrzenie nazw mogą być przydatne w niektórych aplikacjach, ale w moich wcale; powodowały ogromną irytację. To rozwiązanie zadziałało dla mnie.
JYelton,
@John Saunders - Tak, użyłem tego rozwiązania i zdałem sobie sprawę, że masz rację. W odpowiedzi przesyłam zaktualizowane rozwiązanie
Konrad Morawski
6
To rozwiązanie NIE zadziałało u mnie, ponieważ kod usuwa wszystkie atrybuty, a także przestrzenie nazw. Oczywiście kilka zmian może zadziałać, aby sprawdzić, czy usuwany atrybut jest przestrzenią nazw, czy atrybutem
bigfoot,
@KonradMorawski, niestety, nie widzę tutaj twojej odpowiedzi. :(
Rami A.
63

Oznaczona najbardziej użyteczna odpowiedź ma dwie wady:

  • Ignoruje atrybuty
  • Nie działa z elementami „trybu mieszanego”

Oto moje podejście do tego:

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

Przykładowy kod tutaj .

Dexter Legaspi
źródło
Niestety to nie zadziałało, zwrócono ten sam wpisany xml. :(
Rami A.
@RamiA. czy możesz opublikować fragment kodu, abyśmy mogli zobaczyć, na czym polega problem?
Dexter Legaspi
Dla mnie też nie działało. Wydaje mi się, że skoro kopiujesz atrybuty, które po prostu kopiujesz, xmlnsrównież.
MarioDS
1
To działa. Użyłem go ... jednak zdałem sobie sprawę, że nie jest to dokładne czyszczenie w tym sensie, że nie usuwa rzeczywistych atrybutów xmlns, które definiują przestrzeń nazw ... więc zaktualizowałem go, aby to zrobić ... i dodałem przykład treści .
Dexter Legaspi
Trzeba dodać (from a in e.Attributes().DistinctBy(x => x.Name.LocalName)do przypadkulang=""ru-ru"" xml:lang=""ru-ru""
smg
26

obowiązkowa odpowiedź za pomocą 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));
}
Jimmy
źródło
3
Myślę, że możesz pokazać ludziom VB, że mimo wszystko możesz mieć literał XML w C #.
Robert Harvey
1
@Robert, to nie jest literał XML. To jest sznurek. Jest duża różnica!
CoderDennis
Jimmy, jesteś blisko, ale jeszcze go nie ma. :) Piszę ostateczne rozwiązanie na podstawie Twojego pomysłu. Wrzucę to tam.
Peter Stegnar
masz rację :) skoro już to robisz, oferuję własną wersję poprawki.
Jimmy
3
To usuwa wszystkie atrybuty, nie tylko przestrzenie nazw. Zobacz odpowiedź Floriana na naprawę .
Brian
25

To wystarczy :-)

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)));
}
JSC
źródło
Yo, to działa świetnie, nie tylko działa, ale nawet nie wpływa na plik, w którym zapisuje dane, także Xelement przy użyciu metody DescendantAndself. dzięki!
shawn
pracuje dla mnie. Obsługuje również CDATA, które inne rozwiązania tracą po drodze.
paul
16

Podnieś to ponownie, w C # - dodana linia do kopiowania atrybutów:

    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;
    }
Florian Dürrbaum
źródło
1
Działa dla elementu głównego, ale nie dla elementów zagnieżdżonych; wydaje się, że nazwy przestrzeni nazw zostały właśnie zmienione, być może automatycznie przez XElement.ToString ().
Rami A.
Dokładnie to, czego potrzebowałem, aby usunąć wszystkie przestrzenie nazw, ale zachować atrybuty.
Bassie,
10

Obowiązkowa odpowiedź przy użyciu 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>
annakata
źródło
+1 za „obowiązkowe”. :-) Nadal zastanawiam się, dlaczego usunięcie przestrzeni nazw byłoby mądrą decyzją. Prawdopodobnie powoduje awarię i wypala się na <element ns: attr = "a" attr = "b" />.
Tomalak
Jasne, ale każda technika usuwania NS będzie w większym lub mniejszym stopniu. Jeśli chodzi o ważność, mogę powiedzieć, gdzie go potrzebowałem: importowanie XML innej firmy, gdzie nie mogą uporządkować prawidłowego XSD, ale nalegają na przestrzeń nazw. Ostatecznie zasady praktyczności.
annakata
1
@annakata: Rozwiązanie jest prostsze niż myślisz. Przestań włączać. Nie używaj żadnej techniki, która nie obsługuje XML. Jedynym powodem, dla którego wciąż jesteśmy zmuszeni używać takich bzdur, jest to, że ludzie ciągle mówią „tak”, kiedy muszą powiedzieć „nie” nieco częściej. Normy mają ponad 10 lat! Dlaczego jeszcze mamy oprogramowanie, które nie rozumie przestrzeni nazw XML, poza tym, że nadal umożliwiamy jego istnienie?
John Saunders
3
@John - ha, są takie rzeczy, które należy zrobić, i są takie, które zdaniem kierownictwa zostaną zrobione. Wszystko jest najlepsze w najlepszym ze wszystkich możliwych światów.
annakata
1
@Tomalak Jednym z przypadków użycia może być sytuacja, w której musisz przekonwertować na format JSON i deklaracje przestrzeni nazw zakłócają ten proces.
devlord
10

I to jest idealne rozwiązanie, które usunie również elementy XSI. (Jeśli usuniesz xmlns i nie usuniesz XSI, .Net wrzeszczy na ciebie ...)

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, "");
David
źródło
1
Powinienem to przeczytać 2 godziny temu. Wykonałem prawie ten sam regex, jedyną rzecz, która działała, w złożonym XML-u, z wieloma przestrzeniami nazw, atrybutami itp.
TPAKTOPA
Należy pamiętać, że nadal może być konieczne wyczyszczenie elementów, takich jak na przykład <xxx: tagname>. Użyłem następującego kodu (zastrzeżenie, działa na moim komputerze): Regex.Replace(xmlStr, @"<(/?)([^>\s:]+):([^>]+)>", "<$1$3>")
Edwin
9

Wiem, że to pytanie zostało rzekomo rozwiązane, ale nie byłem do końca zadowolony ze sposobu, w jaki zostało wdrożone. Znalazłem inne źródło tutaj na blogach MSDN, które ma nadpisaną XmlTextWriterklasę, która usuwa przestrzenie nazw. Trochę go poprawiłem, aby uzyskać inne rzeczy, które chciałem, takie jak ładne formatowanie i zachowanie elementu głównego. Oto, co mam w tej chwili w swoim projekcie.

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

Klasa

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

Stosowanie

//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);
}
żartobliwy
źródło
1
Twoja odpowiedź jest jedyną, która nie sprawia wrażenia włamania, jednak oryginalny przykład w przywoływanym poście na blogu jest bardziej poprawny, ponieważ jeśli nie usuniesz przestrzeni nazw w węźle głównym, wszystkie węzły potomne i atrybuty bez przestrzeń nazw odziedziczy główną przestrzeń nazw.
tenor
8

To rozwiązanie oparte na zaakceptowanej odpowiedzi Petera Stegnara.

Użyłem go, ale (jak zauważyli andygjp i John Saunders) jego kod ignoruje atrybuty .

Musiałem też zadbać o atrybuty, więc dostosowałem jego kod. Wersja Andy'ego to Visual Basic, to nadal jest C #.

Wiem, że minęło trochę czasu, ale być może pewnego dnia kogoś to uratuje.

    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;
    }
Konrad Morawski
źródło
6

Bardzo podobało mi się miejsce, w którym Dexter tam jedzie, więc przetłumaczyłem to na „płynną” metodę rozszerzenia:

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

Podejście „płynne” pozwala mi to zrobić:

var xml = File.ReadAllText(presentationFile);
var xDoc = XDocument.Parse(xml);
var xRoot = xDoc.Root.WithoutNamespaces();
rasx
źródło
1
Dzięki za to rozwiązanie! Działa świetnie w moim przypadku.
AngieM
1
Więc to było idealne, PONIEWAŻ działało na atrybutach. Mogłem tego używać bez problemu. Dzięki
julian guppy
4

Możesz to zrobić za pomocą 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();
}
Philip Atz
źródło
3

Nieznacznie zmodyfikowana odpowiedź Petera, działałaby dobrze również w przypadku atrybutu, w tym usunięcie przestrzeni nazw i prefiksu. Trochę przepraszam, że kod wygląda trochę brzydko.

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

    }
JackG
źródło
+1 To zadziałało dla mnie. Jednak pozostawia atrybuty, które były częścią definicji przestrzeni nazw (usunięto tylko prefiks xmlns), ale obecnie nie mają one wpływu na serializację.
Rami A.
2

Odpowiedzi Jimmy'ego i Petera były bardzo pomocne, ale w rzeczywistości usunęli wszystkie atrybuty, więc dokonałem niewielkiej modyfikacji:

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
andygjp
źródło
2

Trochę za późno na imprezę na tym, ale oto, czego ostatnio użyłem:

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

(pobrane z tego wątku MSDN )

Edycja Zgodnie z poniższym komentarzem wydaje się, że chociaż usuwa to przedrostek przestrzeni nazw z węzłów, w rzeczywistości nie usuwa atrybutu xmlns. Aby to zrobić, musisz również zresetować nazwę każdego węzła do jego nazwy lokalnej (np. Nazwa bez przestrzeni nazw)

foreach (var node in doc.Root.DescendantNodesAndSelf().OfType<XElement>())
{
    node.Name = node.Name.LocalName;
}
MarcE
źródło
Wydaje się, że nie działa? Znajduje wszystkie deklaracje przestrzeni nazw, ale wywołanie metody Remove () w tej kolekcji nic nie robi. Próbowałem result.ToString (), a wynikowy ciąg nadal ma atrybut xmlns. czy robię coś źle?
Jimmy
Działało na to, czego potrzebowałem w tamtym czasie, ale teraz patrzę wstecz, to nie jest w 100%. Usuwa prefiksy przestrzeni nazw z węzłów (czego potrzebowałem), ale masz rację, pozostawiając atrybut xmlns za sobą. Co dziwne, ten atrybut również nie jest rozpoznawany przez żadną z metod XDocument!
MarcE
1

Aby atrybuty działały, pętla for do dodawania atrybutu powinna przejść po rekursji, należy również sprawdzić, czy 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;
}
user892217
źródło
1

Oto moja wersja Dexter Legaspi C # w VB.NET

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
user2740574
źródło
1

Inne rozwiązanie uwzględniające ewentualne przeplatanie węzłów TEXT i ELEMENT, np .:

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

Kod:

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;
        }
    }
}
szacunek
źródło
1

Bez uciekania się do rozwiązania opartego na XSLT, jeśli chcesz mieć czyste, eleganckie i inteligentne, będziesz potrzebować wsparcia ze strony frameworka, w szczególności wzorca odwiedzających może sprawić, że będzie to proste. Niestety nie jest tutaj dostępny.

Zaimplementowałem to zainspirowane LINQ, ExpressionVisitoraby mieć podobną strukturę. Dzięki temu można zastosować wzorzec gościa do obiektów XML (LINQ-to-). (Przeprowadziłem ograniczone testy, ale działa dobrze, o ile mogę powiedzieć)

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, ta konkretna implementacja wykorzystuje niektóre funkcje .NET 4, aby implementacja była nieco łatwiejsza / czystsza (użycie dynamici domyślne argumenty). Zapewnienie zgodności z .NET 3.5, a może nawet .NET 2.0 nie powinno być trudne.

Następnie, aby zaimplementować gościa, oto uogólniony, który może zmienić wiele przestrzeni nazw (i użyty prefiks).

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

I mała pomocnicza metoda, aby piłka się toczyła:

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

Następnie, aby usunąć przestrzeń nazw, możesz to nazwać tak:

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

Korzystając z tego gościa, możesz napisać, INamespaceMappingManageraby usunąć wszystkie przestrzenie nazw.

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;
        }
    }
}
Jeff Mercado
źródło
1

Proste rozwiązanie, które faktycznie zmienia nazwy elementów w miejscu, nie tworząc kopii, i całkiem nieźle zastępuje atrybuty.

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

Uwaga: nie zawsze zachowuje to oryginalną kolejność atrybutów, ale jestem pewien, że możesz to łatwo zmienić, jeśli jest to dla Ciebie ważne.

Zwróć też uwagę, że może to również spowodować wyjątek, jeśli masz atrybuty XElement, które są unikalne tylko w przestrzeni nazw, na przykład:

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

co naprawdę wydaje się nieodłącznym problemem. Ale ponieważ pytanie wskazywało na wyprowadzenie String, a nie XElement, w tym przypadku możesz mieć rozwiązanie, które wyprowadzi prawidłowy ciąg, który był nieprawidłowym XElement.

Podobała mi się również odpowiedź Joculla przy użyciu niestandardowego XmlWriter, ale kiedy jej spróbowałem, nie zadziałała. Chociaż wszystko wygląda na poprawne, nie mogłem stwierdzić, czy klasa XmlNoNamespaceWriter miała w ogóle jakiś wpływ; zdecydowanie nie usuwał przestrzeni nazw tak, jak chciałem.

Liczydło
źródło
1

Dodanie my to również czyści nazwy węzłów, które mają prefiksy przestrzeni nazw:

    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;
    }
Wolf5
źródło
1

Wypróbowałem kilka pierwszych rozwiązań i nie zadziałały. Głównie problem z usuwaniem atrybutów, jak już wspomnieliśmy. Powiedziałbym, że moje podejście jest bardzo podobne do Jimmy'ego, używając konstruktorów XElement, które przyjmują obiekt jako parametry.

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);
}
sww
źródło
1

moja odpowiedź,
kod lite-most oparty na manipulacji ciągami znaków ,

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;
    }
Si Livan
źródło
1

Oto Regex Wymień jedną wkładkę:

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

Oto próbka: https://regex101.com/r/fopydN/6

Ostrzeżenie: mogą wystąpić przypadki skrajne!

Visar
źródło
0

Odpowiedź user892217 jest prawie poprawna. Nie skompiluje się tak, jak jest, dlatego wymaga niewielkiej korekty wywołania rekurencyjnego:

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;
}
user2789366
źródło
0

To zadziałało dla mnie.

       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();
Scott Parker
źródło
0

Po długich poszukiwaniach rozwiązania tego właśnie problemu, ta strona wydawała się mieć najwięcej wołowiny ... jednak nic nie pasowało dokładnie, więc wybrałem staroświecki sposób i po prostu przeanalizowałem to, co chciałem. Mam nadzieję, że to komuś pomoże. (Uwaga: to również usuwa SOAP lub podobne elementy koperty.)

        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  (i.e. "<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);
    }
LeeT
źródło
0

Bez odtwarzania całej hierarchii węzłów:

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);
    }
}
Stas BZ
źródło
0

Wypróbowałem niektóre rozwiązania, ale jak twierdziło wielu, są pewne skrajne przypadki.

Użyłem niektórych z powyższych wyrażeń regularnych, ale doszedłem do wniosku, że jednoetapowe wyrażenie regularne jest niewykonalne.

Oto moje rozwiązanie, 2-krokowe wyrażenie regularne, znajdź tagi, usuń tagi, nie zmieniaj danych 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)
              )
            );

Na razie działa na mnie w 100%.

user2056154
źródło
-1

Oto rozwiązanie tego problemu oparte na wyrażeniach regularnych ...

    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;
    }
Siddharth
źródło
-1

Myślę, że to jest najkrótsza odpowiedź (ale w przypadku konstrukcji takich jak, będziesz mieć inną dyskusję, mam również wyrażenie regularne do konwersji "<bcm:info></bcm:info>"na „ <info></info>”, ale nie zostało zoptymalizowane, jeśli ktoś mnie o to zapyta, udostępnię to. Więc moje rozwiązanie to:

    public string RemoveAllNamespaces(string xmlDocument)
    {
        return Regex.Replace(xmlDocument, @"\sxmlns(\u003A\w+)?\u003D\u0022.+\u0022", " ");
    }
Leonid
źródło