[c#] C #을 사용하여 XML에서 모든 네임 스페이스를 제거하는 방법은 무엇입니까?

모든 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 #입니다.



답변

음, 여기에 최종 답변이 있습니다. 나는 훌륭한 Jimmy 아이디어 (불행히도 자체가 완전하지 않음)와 완전한 재귀 함수를 사용하여 제대로 작동했습니다.

인터페이스 기반 :

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 % 작동하지만 많은 테스트를 거치지 않았기 때문에 일부 특수한 경우를 다루지 않을 수도 있습니다.하지만 시작하기에 좋은 기준입니다.


답변

태그가 지정된 가장 유용한 답변에는 두 가지 결함이 있습니다.

  • 속성을 무시합니다.
  • “혼합 모드”요소에서는 작동하지 않습니다.

이것에 대한 나의 견해는 다음과 같습니다.

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

여기에 샘플 코드가 있습니다 .


답변

LINQ를 사용한 필수 답변 :

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


답변

그것은 트릭을 할 것입니다 🙂

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


답변

C #에서 다시 선택-속성 복사를위한 줄 추가 :

    static XElement stripNS(XElement root)
    {
        XElement res = new XElement(
            root.Name.LocalName,
            root.HasElements ?
                root.Elements().Select(el => stripNS(el)) :
                (object)root.Value
        );

        res.ReplaceAttributes(
            root.Attributes().Where(attr => (!attr.IsNamespaceDeclaration)));

        return res;
    }


답변

XSLT를 사용한 필수 답변 :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="no" encoding="UTF-8"/>

  <xsl:template match="/|comment()|processing-instruction()">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>


답변

그리고 이것은 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, "");