一、xml命名空间namespace

  1. 先贴一段xml吧。我在做onvif摄像机系统集成时遇到过的。
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl" xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12" xmlns:http="http://schemas.xmlsoap.org/wsdl/http" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2" xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tnshik="http://www.hikvision.com/2011/event/topics" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema"><env:Header><wsadis:MessageID>urn:uuid:e7a13f16-0504-11b4-826c-4419b6438f8b</wsadis:MessageID>
<wsadis:RelatesTo>uuid:b2d3105d-34a2-40cd-b23c-dd70f34b44ca</wsadis:RelatesTo>
<wsadis:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsadis:To>
<wsadis:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsadis:Action>
<d:AppSequence InstanceId="1525026063" MessageNumber="1448"/>
</env:Header>
<env:Body><d:ProbeMatches><d:ProbeMatch><wsadis:EndpointReference><wsadis:Address>urn:uuid:e7a13f16-0504-11b4-826c-4419b6438f8b</wsadis:Address>
</wsadis:EndpointReference>
<d:Types>dn:NetworkVideoTransmitter tds:Device</d:Types>
<d:Scopes>onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/Profile/Streaming onvif://www.onvif.org/Profile/G onvif://www.onvif.org/hardware/DS-2CD3210D-I5 onvif://www.onvif.org/name/DS-2CD3210D-I5 onvif://www.onvif.org/location/city/hangzhou</d:Scopes>
<d:XAddrs>http://192.168.0.13/onvif/device_service http://[fd36:5454:29e4:0:4619:b6ff:fe43:8f8b]/onvif/device_service</d:XAddrs>
<d:MetadataVersion>10</d:MetadataVersion>
</d:ProbeMatch>
</d:ProbeMatches>
</env:Body>
</env:Envelope>
  1. 如上面的xml所示。每一个节点前面都是带了前缀的,用冒号隔开,这个叫做xml的命名空间namespace。
  2. 命名空间的作用:避免相同名字所导致的命名冲突!
    在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。使用命名空间,也就是使用前缀可以避免命名冲突。这跟我们平时写c++和c#时候的命名空间是基本一个道理的。

二、如何解析带有命名空间的xml

  1. 就拿上面那段xml来做个分析
<d:XAddrs>http://192.168.0.13/onvif/device_service http://[fd36:5454:29e4:0:4619:b6ff:fe43:8f8b]/onvif/device_service</d:XAddrs>
  1. 我想获取XAddrs,最简单的办法是GetElementsByTagName(“d:XAddrs”)这种方法直接获取。但是,很明显不同厂家和供应商所提供的的产品,前缀是不一样的,也就是XAddrs前面的d不是固定的。一旦前缀不是d,会导致GetElementsByTagName(“d:XAddrs”)这个方法失效。
  2. 所以要根据实际获取到的xml,提取出前缀。
  3. XAddrs的前缀是在一开始的xmlns那里定义的。
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl" xmlns:tst="http://www.onvif.org/ver10/storage/wsdl" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:dn="http://www.onvif.org/ver10/network/wsdl" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl" xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12" xmlns:http="http://schemas.xmlsoap.org/wsdl/http" xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2" xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2" xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2" xmlns:trc="http://www.onvif.org/ver10/recording/wsdl" xmlns:tse="http://www.onvif.org/ver10/search/wsdl" xmlns:trp="http://www.onvif.org/ver10/replay/wsdl" xmlns:tnshik="http://www.hikvision.com/2011/event/topics" xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl" xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema"><env:Header>
  1. 上面贴的xmlns内容有点长,和d有关的就一句
xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
  1. 这句话的意思是,discovery的节点添加的是d作为前缀。
  2. 举个别的厂家的例子吧
xmlns:tns="http://schemas.xmlsoap.org/ws/2005/04/discovery"
  1. 上面那个厂家的discovery对应的前缀就是tns了。

三、c#示例代码

  1. 思路就很简单了。
    • 在解析xml开头的地方先获取xmlns。
    • 根据自己要解析和关注的节点去获取xmls(namespace)就行了,当然也可以全部获取。
    • 调用节点的时候,格式为(namespace+冒号+节点名称)
  2. 我用文章最开头那段xml举个例子,获取XAddrs和Address。

XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlStr);//xmlStr是读取到的xml字符串,也就是上面文章开头那一段
xaddrPrefix = doc.DocumentElement.GetPrefixOfNamespace("http://schemas.xmlsoap.org/ws/2005/04/discovery");//XAddrs的前缀
uuidPrefix= doc.DocumentElement.GetPrefixOfNamespace("http://schemas.xmlsoap.org/ws/2004/08/addressing");//Address的前缀
Console.WriteLine(xaddrPrefix);
Console.WriteLine(uuidPrefix);
XmlNodeList xaddrsElemList = doc.GetElementsByTagName(xaddrPrefix+":XAddrs");//读取相应的元素,因为有可能不止一个元素,所以返回的结果是List
XmlNodeList uuidElemList = doc.GetElementsByTagName(uuidPrefix + ":Address");
for (int i = 0; i < xaddrsElemList.Count; i++)
            {
                Console.WriteLine(xaddrsElemList[i].InnerXml);
            }
for (int i = 0; i < uuidElemList.Count; i++)
            {
                Console.WriteLine(uuidElemList[i].InnerXml);
            }

后记

还有几点需要说明一下的:
1. 其中的url “http://schemas.xmlsoap.org/ws/2005/04/discovery”和”http://schemas.xmlsoap.org/ws/2004/08/addressing”是onvif标准里面定义的,一般来说是不会变化的。所以通过这两个值,可以获取到相应的xmlns的值。
2. 获取到xmlns之后,再去获取node和element的方式有很多种,我上面只是举例而已。





http://xzh.i3geek.com

爱唠叨的老鱼

爱唠叨的老鱼

技术经理,个人站长,创业者

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据