在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。假如这两个 XML 文档被一起使用,由于两个文档都包含带有不同内容和定义的
元素,就会发生命名冲突。XML 解析器无法确定如何处理这类冲突。使用前缀来避免命名冲突
此文档带有某个表格中的信息:
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
此 XML 文档携带着有关一件家具的信息:
<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
现在,命名冲突不存在了,这是由于两个文档都使用了不同的名称来命名它们的<table>
元素 (<h:table> 和 <f:table>
)。通过使用前缀,我们创建了两种不同类型的 <table>
元素。
使用命名空间(Namespaces)
这个 XML 文档携带着某个表格中的信息:
<h:table xmlns:h="http://www.w3.org/TR/html4/">
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
此 XML 文档携带着有关一件家具的信息:
<f:table xmlns:f="http://www.w3school.com.cn/furniture">
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
与仅仅使用前缀不同,我们为 <table>
标签添加了一个 xmlns 属性,这样就为前缀赋予了一个与某个命名空间相关联的限定名称。XML Namespace (xmlns) 属性
XML 命名空间属性被放置于元素的开始标签之中,并使用以下的语法:
xmlns:namespace-prefix=”namespaceURI”
当命名空间被定义在元素的开始标签中时,所有带有相同前缀的子元素都会与同一个命名空间相关联。
为元素定义默认的命名空间可以让我们省去在所有的子元素中使用前缀的工作。
请使用下面的语法:
xmlns=”namespaceURI”
这个 XML 文档携带着某个表格中的信息:
<table xmlns="http://www.w3.org/TR/html4/">
<tr>
<td>Apples</td>
<td>Bananas</td>
</tr>
</table>
此 XML 文档携带着有关一件家具的信息:
<table xmlns="http://www.w3school.com.cn/furniture">
<name>African Coffee Table</name>
<width>80</width>
<length>120</length>
</table>
(转原文http://www.cnblogs.com/mgen/archive/2011/05/24/2056025.html)
众所周知,XmlDocument可以进行XPath查询,但实际上这里所说的XPath查询仅限于没有命名空间(没有xmlns属性)的XML,一旦遇到有命名空间的XML,对应XPath查询都会无结果。
为什么会这样呢?MSDN的相应函数有解释(参考:http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.selectsinglenode.aspx)
If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get any nodes selected
意思就是如果XPath表达式没有加前缀(如a:b中前缀是a),那么所查询节点(注意属性也可以是节点)的命名空间URI就应该是空值(也是默认值),否则XPath不会返回结果。
你需要记住:在XmlDocument中用XPath查询某一节点时,只要它的命名空间值不是空值,那么你必须给它一个前缀, 用这个前缀代表这个节点的命名空间值!这些前缀是通过XmlNamespaceManager类添加的,使用时将XmlNamespaceManager 传入SelectNodes或SelectSingleNode中即可。这也是为什么上面说“如果节点有默认命名空间,那么还得手动向 XmlNamespaceManager添加前缀和命名空间值”的原因。
另外构造一个XmlNamespaceManager需要XmlNameTable对象,这个对象可以从XmlDocument.NameTable和XmlReader.NameTable属性中得到。
例如:
<?xmlversion="1.0" encoding="utf-8"?>
<rootxmlns="dotnet" xmlns:w="wpf">
<!-- xmlns: dotnet -->
<a>data in a</a>
<!-- xmlns: dotnet -->
<w:b>data in b</w:b>
<!-- xmlns: wpf -->
<cxmlns="silverlight">
<!-- xmlns: silverlight -->
<w:d>
<!-- xmlns: wpf -->
<e>data in e</e>
<!-- xmlns: silverlight -->
</w:d>
</c>
</root>
比如说查询上面XML中的节点e,分析位置节点e位于:root->c->d->e,然后将所需命名空间值加入到 XmlNamespaceManager中(前缀名称无所谓,只要在XPath一致即可),查询即可成功,如下代码:
/*
* 假设上面XML文件在C:\a.txt中
* 下面代码会查询目标节点e,并输出数据:data in e
* */
var xmlDoc =newXmlDocument();
xmlDoc.Load(@"C:\a.txt");
//加入命名空间和前缀
var xmlnsm =newXmlNamespaceManager(xmlDoc.NameTable);
xmlnsm.AddNamespace("d", "dotnet");
xmlnsm.AddNamespace("s", "silverlight");
xmlnsm.AddNamespace("w", "wpf");
var node = xmlDoc.SelectSingleNode("/d:root/s:c/w:d/s:e", xmlnsm);
Console.WriteLine(node.InnerText);
//输出:data in e
发现某个节点有瑕疵想换一个名称:
思路如下。先使用XmlDocument读取xml文件。然后在修改的结点处如“DLG2000二级元数据_非修测”用结点的父节点插入CreateElement相同级别的结点如DLG2000二级元数据。然后将旧结点的InnerXml赋值给新结点。然后用修改的结点的父节点调用ReplaceChild将新结点newElement替换旧结点rootElement,然后保存即可。具体代码如下。
XmlDocument pXmlDocument = new XmlDocument();
pXmlDocument.Load(@"D:\A01.xml");
XmlElement rootElement = pXmlDocument.DocumentElement;
XmlElement newElement = pXmlDocument.CreateElement("DLG2000二级元数据");
newElement.InnerXml = rootElement.InnerXml;
pXmlDocument.ReplaceChild(newElement, rootElement);
pXmlDocument.Save(@"D:\A01.xml");
至于去掉xml文档的命名空间,可以直接用字符串替换解决:
//创建xml文档
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(@"C:\Users\Tony\Downloads\统一标准报文格式.xml");
//去掉注释 和命名空间
string newXml = System.Text.RegularExpressions.Regex.Replace(xmlDoc.OuterXml,@"(xmlns:?[^=]*=[""][^""]*[""])", "",System.Text.RegularExpressions.RegexOptions.IgnoreCase |
System.Text.RegularExpressions.RegexOptions.Multiline);