如何用Python和XPath仅获取显式定义默认命名空间的XML元素
问题:用XPath筛选显式声明默认命名空间的XML元素
我用Python的lxml解析XML字符串,需要编写XPath表达式,只获取那些**自身显式定义了默认命名空间(无前缀的xmlns属性)**的元素。
当前示例代码:
from lxml import etree xml = ''' <TELCAL_DATAMANAGER_BDNT_1 xmlns="urn:schemas-cosylab-com:BulkDataNTReceiver:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:schemas-cosylab-com:BulkDataNTReceiver:1.0 BulkDataNTReceiver.xsd"> <ReceiverStream Name="InterferometricStream1" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> <ReceiverStream Name="InterferometricStream2" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> <ReceiverStream Name="InterferometricStream3" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> </TELCAL_DATAMANAGER_BDNT_1> ''' root = etree.fromstring(xml) # 原XPath,会返回所有继承了命名空间的元素 elements = root.xpath("//*[namespace-uri()!='' and not(local-name()='*')]") for element in elements: print(element)
执行后返回所有带命名空间的元素(包括继承根命名空间的子元素),但我只需要自身显式声明xmlns="urn:schemas-cosylab-com:BulkDataNTReceiver:1.0"的TELCAL_DATAMANAGER_BDNT_1元素。
解决方案
原XPath的问题在于,它筛选的是所有拥有非空命名空间的元素,而XML中子元素会自动继承父元素的默认命名空间,所以所有子元素都符合条件。要筛选自身显式声明了默认命名空间的元素,需要检查元素是否带有xmlns属性。
修改后的XPath表达式为:
//*[@xmlns]
或者更严谨地针对XML命名空间属性的特殊规则,使用:
//*[attribute::xmlns]
修改后的代码:
from lxml import etree xml = ''' <TELCAL_DATAMANAGER_BDNT_1 xmlns="urn:schemas-cosylab-com:BulkDataNTReceiver:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:schemas-cosylab-com:BulkDataNTReceiver:1.0 BulkDataNTReceiver.xsd"> <ReceiverStream Name="InterferometricStream1" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> <ReceiverStream Name="InterferometricStream2" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> <ReceiverStream Name="InterferometricStream3" participantPerStream="true"> <ReceiverFlow Name="FullSpectralFlow" cbReceiveAvgProcessTimeoutSec="0.0018" multicastAddress="225.3.2.100"></ReceiverFlow> <ReceiverFlow Name="ChannelAveragesFlow" multicastAddress="225.3.2.200"></ReceiverFlow> <ReceiverFlow Name="WVRFlow" multicastAddress="225.3.2.30"></ReceiverFlow> </ReceiverStream> </TELCAL_DATAMANAGER_BDNT_1> ''' root = etree.fromstring(xml) # 修改后的XPath,仅返回自身显式声明默认命名空间的元素 elements = root.xpath("//*[@xmlns]") for element in elements: print(element)
执行后输出:
<Element {urn:schemas-cosylab-com:BulkDataNTReceiver:1.0}TELCAL_DATAMANAGER_BDNT_1 at 0x7f8100613640>
补充说明
如果需要精准匹配特定的默认命名空间值,可以进一步过滤:
//*[@xmlns='urn:schemas-cosylab-com:BulkDataNTReceiver:1.0']
内容的提问来源于stack exchange,提问作者fjcaro
相关产品推荐
相关产品推荐

