C#を使用してXMLからすべての名前空間を削除する方法


104

すべてのXML要素から名前空間を削除するためのクリーンでエレガントでスマートなソリューションを探していますか?それを行うにはどのように機能しますか?

定義されたインターフェース:

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

NSを削除するサンプルXML:

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

ソリューションの優先言語は、.NET 3.5 SP1上のC#です。


@JohnSaunders:あなたは正しいです。しかし、この特定のケースでは、システム統合を行う必要があります。そして、これが当時の唯一の選択肢でした。
Peter Stegnar 2013年

@PeterStegnarエラーは通常、レガシー形式を作成したハッカーです。多くの場合、開発者はxmlを慢性的に誤用します。名前空間は、放り投げられる最初の非常に重要な機能です。
Gusdor 2014年

回答:


103

さて、これが最終的な答えです。私は素晴らしいジミーのアイデア(残念ながらそれ自体は完全ではありません)と完全な再帰関数を使用して正しく動作しました。

インターフェースに基づく:

string RemoveAllNamespaces(string xmlDocument);

ここでは、XML名前空間を削除するための最終的なクリーンでユニバーサルなC#ソリューションを示します。

//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%動作していますが、あまりテストしていないため、一部の特殊なケースはカバーされていない可能性があります...しかし、開始するには良いベースです。


8
それは名前空間を持つ属性でどのようにうまく機能しますか?実際、コードは属性を完全に無視します。
John Saunders、

6
名前空間は一部のアプリケーションでは役立つかもしれませんが、私の場合はまったくそうではありません。彼らは大きな迷惑をかけていました。この解決策は私にとってうまくいきました。
JYelton

@ジョン・サンダース-ええ、私はそのソリューションを使用しましたが、あなたが正しいと気づきました。私は回答として更新されたソリューションを投稿しています
Konrad Morawski、2009

6
コードはすべての属性と名前空間を削除するため、この解決策は私には機能しませんでした。もちろん、削除される属性が名前空間または属性であるかどうかを確認するためにいくつかの変更が機能する可能性があります
bigfoot

@KonradMorawski、残念ながら、私はここにあなたの答えを見ません。:(
Rami A.

63

タグ付けされた最も有用な回答には2つの欠点があります。

  • 属性を無視します
  • 「混合モード」要素では機能しません

これは私の考えです:

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

サンプルコードはこちら


残念ながら、これは私にはうまくいきませんでした。入力した同じxmlが返されました。:(
ラミA.

@RamiA。コードのスニペットを投稿して、問題が何であるかを確認できますか?
デクスターLegaspi 2013

私もうまくいきませんでした。属性をコピーしているxmlnsので、単純にコピーしているだけだと思います。
MarioDS 2014年

1
これは機能します。私はそれを使用しました...ただし、名前空間を定義する実際のxmlns属性を削除しないという意味で、完全なクリーニングではないことに気づきました...それで、それを行うように更新しました...そして要旨の例を追加しました。
デクスターLegaspi

(from a in e.Attributes().DistinctBy(x => x.Name.LocalName)ケースに追加する必要がありますlang=""ru-ru"" xml:lang=""ru-ru""
smg 2015年

26

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

3
結局のところ、C#でXMLリテラルを持つことができるVBの人々を示すことができると思います。
Robert Harvey

1
@Robert、それはXMLリテラルではありません。文字列です。大きな違いがあります!
CoderDennis 2009年

ジミー、あなたは近くにいますが、まだそこにはいません。:)私はあなたのアイデアに基づいて最終的な解決策を書いています。そこで投稿します。
Peter Stegnar 2009年

あなたが正しい:)あなたがそれにいる間、私は自分のバージョンの修正を提供します。
ジミー、

3
これにより、名前空間だけでなく、すべての属性が削除されます。修正については、florianの回答を参照してください。
ブライアン

25

それはトリックを行います:-)

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

これはうまく機能しますが、機能するだけでなく、データを書き込んでいるファイルにも、DescendantAndselfメソッドを使用してXelementにも影響を与えません。ありがとう!
ショーン

私のために働く。他のソリューションが途中で緩んでいるCDATAも処理します。
ポール

16

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

1
ルート要素では機能しますが、ネストされた要素では機能しません。名前空間は、おそらくXElement.ToString()によって自動的に名前が変更されるようです。
Rami A.

名前空間をすべて削除し、属性は保持するために必要なもの。
Bassie 2017

10

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>

「必須」の場合は+1。:-)名前空間を削除することが賢明な決定になるのはなぜだろうと私はまだ疑問に思います。これはおそらく<element ns:attr = "a" attr = "b" />でクラッシュして書き込みます。
Tomalak 2009年

確かに、しかし、すべてのNS除去テクニックは多かれ少なかれ程度になります。妥当性として、私がどこでそれを必要としているかを説明できます。サードパーティのXMLをインポートして、有効なXSDを分類できないが、ネームスペースを要求する場合。実用性が最終的に決まります。
アナカタ09年

1
@アンナカタ:ソリューションはあなたが考えるよりも簡単です。有効化を停止します。XMLを理解しない手法の使用を拒否する。私たちがまだそのようなゴミを使わざるを得ない唯一の理由は、人々が「いいえ」をもう少し頻繁に言う必要があるときに「はい」と言い続けるからです。基準は10年以上前のものです!それでも引き続き存在できるようにすることを除いて、XML名前空間を理解しないソフトウェアがまだあるのはなぜですか?
ジョンサンダース、

3
@ジョン-ハ、やらなければならないことがある、そして経営陣がやると考えているものがある。すべては、可能な限り最高の世界で最高のものです。
穴形09年

1
@Tomalak 1つのユースケースは、JSONに変換する必要があり、名前空間宣言がそのプロセスに干渉する場合です。
devlord

10

そして、これは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, "");

1
これは2時間前に読むべきです。ほぼ同じ正規表現、多くの名前空間、属性などを持つ複雑なXMLで機能する唯一の正規表現でした
TPAKTOPA

ただし、<xxx:tagname>などの要素をクリーンアップする必要がある場合もあります。私は次のコードを使用しました(免責事項、私のマシンで動作します): Regex.Replace(xmlStr, @"<(/?)([^>\s:]+):([^>]+)>", "<$1$3>")
エドウィン

9

この質問はおそらく解決されていると思いますが、その実装方法には完全に満足していませんでした。XmlTextWriter名前空間を削除するオーバーライドされたクラスが含まれている別のソースがMSDNブログで見つかりました。ルート要素を適切にフォーマットしたり保持したりするなど、他に必要なものがいくつかあるように少し調整しました。ここに私が現在プロジェクトに持っているものがあります。

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

1
あなたの答えはハックのように感じられない唯一のものですが、参照されたブログ投稿の元のサンプルはより正確です。ルートノードの名前空間を削除しないと、すべての子ノードと属性が名前空間はルート名前空間を継承します。
2013年

8

これは、Peter Stegnarの承認された回答に基づくソリューションです。

私はそれを使用しましたが、(andygjpとJohn Saundersが述べたように)彼のコードは属性を無視します

私も属性に注意する必要があったので、彼のコードを適応させました。Andyのバージョンは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;
    }

6

私はDexterがどこに向かっているのか本当に気に入ったので、「流暢な」拡張メソッドに変換しました。

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

「流暢な」アプローチでこれを行うことができます。

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

1
この解決策をありがとう!私の問題に最適です。
AngieM 2017年

1
したがって、これは属性で機能したため、理想的でした。問題なく使用できました。ありがとう
julian guppy 2017年

4

あなたは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

ピーターの答えをわずかに変更しました。これは、名前空間と接頭辞の削除を含め、属性に対しても正常に機能します。コードを少し気の毒に見えます。

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

    }

+1これでうまくいきました。ただし、名前空間定義の一部であった属性は残されます(xmlnsプレフィックスのみが削除されます)が、現時点ではシリアル化には影響しません。
Rami A.

2

ジミーとピーターの返信はとても役に立ちましたが、実際にはすべての属性が削除されたため、少し変更しました。

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

2

これでパーティーに少し遅れましたが、最近使ったものは次のとおりです。

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

(このMSDNスレッドから取得)

編集以下のコメントのとおり、これによりノードからネームスペースプレフィックスが削除されますが、実際にはxmlns属性は削除されないようです。そのためには、各ノードの名前をローカル名にリセットする必要もあります(たとえば、名前から名前空間を差し引いたもの)。

foreach (var node in doc.Root.DescendantNodesAndSelf().OfType<XElement>())
{
    node.Name = node.Name.LocalName;
}

動作していないようですか?すべての名前空間宣言を検索しますが、そのコレクションでRemove()を呼び出しても何も起こりません。result.ToString()を試しましたが、結果の文字列にはまだxmlns属性が残っています。私は何か間違ったことをしていますか?
ジミー

それは当時必要だったものでうまくいきましたが、今では振り返ってみると100%ではありません。それはノードから名前空間プレフィックスを削除します(これは私が必要としたものです)が、xmlns属性を残してそれについて正しいです。奇妙なことに、その属性はどのXDocumentメソッドでも認識されません。
MarcE 2018

1

属性が機能するためには、属性を追加するための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

これが私のデクスターLegaspi C#バージョンの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

1

TEXTノードとELEMENTノードをインターリーブする可能性を考慮した別のソリューション。例:

<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

XSLTベースのソリューションに頼らずに、クリーンでエレガント、そしてスマートにしたい場合は、フレームワークからのサポートが必要になります。特に、ビジターパターンではこれが簡単になります。残念ながら、ここでは利用できません。

LINQにExpressionVisitor似た構造を持つようにインプリメントしました。これにより、ビジターパターンを(LINQ-to-)XMLオブジェクトに適用できます。(私はこれについて限られたテストを行いましたが、私が知る限りではうまくいきます)

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

1

コピーを作成するのではなく、実際に要素の名前を変更する単純なソリューションで、属性を置き換えるのに非常に優れています。

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属性がある場合、これも例外をスローする可能性があることに注意してください。

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

これは本当に固有の問題のようです。しかし、質問はXElementではなく文字列を出力することを示していたため、この場合、無効なXElementである有効な文字列を出力する解決策が考えられます。

また、カスタムXmlWriterを使用したjocullの回答も気に入りましたが、試してもうまくいきませんでした。すべて正しいように見えますが、XmlNoNamespaceWriterクラスがまったく効果があるかどうかはわかりませんでした。名前空間を削除したくなかったのは間違いありません。


1

名前空間接頭辞を持つノードの名前も削除する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;
    }

1

最初のいくつかの解決策を試しましたが、うまくいきませんでした。主に、他の属性のように削除される属性の問題はすでに述べています。私のアプローチは、オブジェクトをパラメーターとして取るXElementコンストラクターを使用するという点で、Jimmyと非常に似ています。

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

私の答えは、文字列操作ベースの
最もライトなコードです。

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

これが正規表現の1つのライナーの交換です。

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

これがサンプルです:https : //regex101.com/r/fopydN/6

警告:エッジケースがあるかもしれません!


0

user892217の答えはほぼ正しいです。そのままではコンパイルできないため、再帰呼び出しを少し修正する必要があります。

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

0

これでうまくいきました。

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

0

この特定の問題の解決策を何度も検索したところ、この特定のページが最も牛肉を持っているように見えました...しかし、まったく正確に一致するものはなかったので、昔ながらの方法を使用して、必要なものを解析しました。これが誰かを助けることを願っています。(注:これにより、SOAPまたは同様のエンベロープの要素も削除されます。)

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

0

ノード階層全体を再作成せずに:

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

0

私はいくつかの解決策を試しましたが、多くの人が述べたように、いくつかのエッジケースがあります。

上記の正規表現の一部を使用しましたが、1ステップの正規表現は実行可能ではないとの結論に達しました。

だからここに私の解決策があります、2ステップの正規表現、タグを検索、タグ内で削除、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)
              )
            );

今のところ、100%働いています。


-1

これは、この問題に対する正規表現ベースのソリューションです...

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

-1

これは最も短い答えだと思います(ただし、のような構成の場合は、別のディスカッションがあります。"<bcm:info></bcm:info>"" <info></info>" に変換する正規表現もありますが、最適化されていません。

    public string RemoveAllNamespaces(string xmlDocument)
    {
        return Regex.Replace(xmlDocument, @"\sxmlns(\u003A\w+)?\u003D\u0022.+\u0022", " ");
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.