모든 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, "");