Как удалить все пространства имен из XML с C #? - PullRequest
96 голосов
/ 12 июня 2009

Я ищу чистое, элегантное и умное решение для удаления пространств имен из всех элементов XML? Как бы функционировал, чтобы это выглядело?

Определенный интерфейс:

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

Пример XML для удаления 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>

Предпочтительным языком решения является C # в .NET 3.5 SP1.

Ответы [ 30 ]

3 голосов
/ 14 декабря 2012

Вы можете сделать это, используя 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();
}
3 голосов
/ 13 августа 2012

Слегка измененный ответ Питера, это также хорошо работает для атрибута, включая удаление пространства имен и префикса. Немного извините за код выглядит немного некрасиво.

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

    }
2 голосов
/ 08 октября 2010

Ответы Джимми и Питера очень помогли, но они фактически удалили все атрибуты, поэтому я внес небольшое изменение:

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
1 голос
/ 02 сентября 2013

Вот моя VB.NET-версия 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
1 голос
/ 29 августа 2012

Чтобы атрибуты работали, цикл for для добавления атрибута должен идти после рекурсии, также необходимо проверить, 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;
}
1 голос
/ 10 сентября 2013

Другое решение, которое учитывает возможное чередование узлов TEXT и ELEMENT, например ::100100

<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;
        }
    }
}
1 голос
/ 08 сентября 2015

Я попробовал первые несколько решений и у меня не получилось. В основном проблема с удалением атрибутов, как уже упоминалось ранее. Я бы сказал, что мой подход очень похож на Джимми с использованием конструкторов XElement, которые принимают объект в качестве параметров.

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);
}
1 голос
/ 03 ноября 2017

Немного опоздал на вечеринку, но вот что я недавно использовал:

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

(взято из этой MSDN Thread )

Редактировать В соответствии с комментарием ниже, кажется, что, хотя это удаляет префикс пространства имен из узлов, оно фактически не удаляет атрибут xmlns. Для этого вам также необходимо сбросить имя каждого узла на его локальное имя (например, имя минус пространство имен)

foreach (var node in doc.Root.DescendantNodesAndSelf().OfType<XElement>())
{
    node.Name = node.Name.LocalName;
}
1 голос
/ 10 сентября 2015

мой ответ, на основе строковых манипуляций,
самый легкий код,

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;
    }
1 голос
/ 07 мая 2015

Добавление my, которое также очищает имя узлов, имеющих префиксы пространства имен:

    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;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...