我正在寻找干净,优雅和智能的解决方案来从所有XML元素中删除名称空间?如何做到这一点的功能?
定义的界面:
public interface IXMLUtils
{
string RemoveAllNamespaces(string xmlDocument);
}
Run Code Online (Sandbox Code Playgroud)
示例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>
Run Code Online (Sandbox Code Playgroud)
在我们调用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>
Run Code Online (Sandbox Code Playgroud)
解决方案的优先语言是.NET 3.5 SP1上的C#.
Pet*_*nar 100
好吧,这是最后的答案.我使用了很棒的Jimmy想法(遗憾的是它本身并不完整)和完整的递归功能才能正常工作.
基于界面:
string RemoveAllNamespaces(string xmlDocument);
Run Code Online (Sandbox Code Playgroud)
我在这里代表用于删除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)));
}
Run Code Online (Sandbox Code Playgroud)
它是100%工作,但我没有测试它,所以它可能不会涵盖一些特殊情况...但它是良好的基础开始.
Dex*_*spi 62
标记最有用的答案有两个缺陷:
以下是我对此的看法:
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);
}
Run Code Online (Sandbox Code Playgroud)
这里有示例代码.
Jim*_*mmy 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));
}
Run Code Online (Sandbox Code Playgroud)
小智 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)));
}
Run Code Online (Sandbox Code Playgroud)
小智 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;
}
Run Code Online (Sandbox Code Playgroud)
使用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>
Run Code Online (Sandbox Code Playgroud)
我知道这个问题应该已经解决了,但我对它的实施方式并不完全满意.我在MSDN博客上发现了另一个来源,它有一个覆盖XmlTextWriter了名称空间的重写类.我稍微调整了一下以获得我想要的其他东西,比如漂亮的格式化和保留根元素.这是我目前项目中的内容.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
//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);
}
Run Code Online (Sandbox Code Playgroud)
小智 9
这是一个完美的解决方案,也将删除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, "");
Run Code Online (Sandbox Code Playgroud)
这是基于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;
}
Run Code Online (Sandbox Code Playgroud)
我真的很喜欢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));
}
Run Code Online (Sandbox Code Playgroud)
"流利"的方法允许我这样做:
var xml = File.ReadAllText(presentationFile);
var xDoc = XDocument.Parse(xml);
var xRoot = xDoc.Root.WithoutNamespaces();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
146050 次 |
| 最近记录: |