使用ElementTree从XML中获取值



我试图从这样的XML文件中获取值:

<?xml version="1.0"?>
<DeviceStorage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Objects>
<Object Type="OBJECT_ANALOG_OUTPUT" Instance="5">
<Properties>
<Property Id="PROP_OBJECT_IDENTIFIER" Tag="BACNET_APPLICATION_TAG_OBJECT_ID">
<Value>OBJECT_ANALOG_OUTPUT:5</Value>
</Property>
<Property Id="PROP_OBJECT_NAME" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>B'JC2415'DUV'Y1</Value>
</Property>
<Property Id="PROP_OBJECT_TYPE" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>1</Value>
</Property>
<Property Id="3006" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>3</Value>
</Property>
<Property Id="PROP_DESCRIPTION" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>Analog out Y1</Value>
</Property>
<Property Id="3001" Tag="BACNET_APPLICATION_TAG_OBJECT_ID">
<Value>201:54</Value>
</Property>
<Property Id="PROP_PROFILE_NAME" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>7-BA-PX-AO-SBCv10.02</Value>
</Property>
<Property Id="3121" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>Building</Value>
<Value>JET-C2.4-15</Value>
<Value>DUV</Value>
<Value>Analog out Y1</Value>
</Property>
<Property Id="3234" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>B'JC2415'DUV'Y1</Value>
</Property>
<Property Id="PROP_PRESENT_VALUE" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="PROP_STATUS_FLAGS" Tag="BACNET_APPLICATION_TAG_BIT_STRING">
<Value>0000</Value>
</Property>
<Property Id="PROP_EVENT_STATE" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>0</Value>
</Property>
<Property Id="PROP_RELIABILITY" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>0</Value>
</Property>
<Property Id="PROP_OUT_OF_SERVICE" Tag="BACNET_APPLICATION_TAG_BOOLEAN">
<Value>False</Value>
</Property>
<Property Id="PROP_UNITS" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>98</Value>
</Property>
<Property Id="PROP_RESOLUTION" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0.1</Value>
</Property>
<Property Id="PROP_PRIORITY_ARRAY" Tag="BACNET_APPLICATION_TAG_NULL">
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
<Value />
</Property>
<Property Id="PROP_RELINQUISH_DEFAULT" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="PROP_COV_INCREMENT" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0.1</Value>
</Property>
<Property Id="PROP_TIME_DELAY" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>1</Value>
</Property>
<Property Id="PROP_NOTIFICATION_CLASS" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>32</Value>
</Property>
<Property Id="PROP_HIGH_LIMIT" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>100</Value>
</Property>
<Property Id="PROP_LOW_LIMIT" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="PROP_DEADBAND" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0.5</Value>
</Property>
<Property Id="PROP_LIMIT_ENABLE" Tag="BACNET_APPLICATION_TAG_BIT_STRING">
<Value>11</Value>
</Property>
<Property Id="PROP_EVENT_ENABLE" Tag="BACNET_APPLICATION_TAG_BIT_STRING">
<Value>111</Value>
</Property>
<Property Id="PROP_ACKED_TRANSITIONS" Tag="BACNET_APPLICATION_TAG_BIT_STRING">
<Value>111</Value>
</Property>
<Property Id="PROP_NOTIFY_TYPE" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>0</Value>
</Property>
<Property Id="PROP_EVENT_TIME_STAMPS" Tag="BACNET_APPLICATION_TAG_CONTEXT_SPECIFIC_DECODED">
<Value>1/1/0001 12:00:00 AM;1/1/0001 12:00:00 AM</Value>
<Value>1/1/0001 12:00:00 AM;1/1/0001 12:00:00 AM</Value>
<Value>1/1/0001 12:00:00 AM;1/1/0001 12:00:00 AM</Value>
</Property>
<Property Id="PROP_DEVICE_TYPE" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value />
</Property>
<Property Id="3000" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value />
</Property>
<Property Id="3005" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>4</Value>
</Property>
<Property Id="3059" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>81</Value>
<Value>6</Value>
<Value>3</Value>
<Value>3</Value>
<Value>104</Value>
<Value>4</Value>
<Value>3</Value>
<Value>3</Value>
<Value>35</Value>
<Value>10</Value>
<Value>1</Value>
<Value>1</Value>
<Value>36</Value>
<Value>5</Value>
<Value>1</Value>
<Value>0</Value>
<Value>130</Value>
<Value>5</Value>
<Value>1</Value>
<Value>0</Value>
<Value>3011</Value>
<Value>10</Value>
<Value>3</Value>
<Value>3</Value>
<Value>45</Value>
<Value>10</Value>
<Value>5</Value>
<Value>5</Value>
<Value>59</Value>
<Value>10</Value>
<Value>5</Value>
<Value>5</Value>
<Value>25</Value>
<Value>10</Value>
<Value>1</Value>
<Value>1</Value>
<Value>113</Value>
<Value>4</Value>
<Value>3</Value>
<Value>3</Value>
<Value>3122</Value>
<Value>10</Value>
<Value>3</Value>
<Value>3</Value>
<Value>3114</Value>
<Value>10</Value>
<Value>3</Value>
<Value>3</Value>
<Value>17</Value>
<Value>7</Value>
<Value>3</Value>
<Value>0</Value>
<Value>72</Value>
<Value>10</Value>
<Value>5</Value>
<Value>0</Value>
<Value>3243</Value>
<Value>7</Value>
<Value>3</Value>
<Value>0</Value>
<Value>0</Value>
<Value>5</Value>
<Value>1</Value>
<Value>0</Value>
<Value>3014</Value>
<Value>5</Value>
<Value>3</Value>
<Value>0</Value>
<Value>3015</Value>
<Value>5</Value>
<Value>3</Value>
<Value>0</Value>
<Value>3019</Value>
<Value>8</Value>
<Value>5</Value>
<Value>3</Value>
<Value>3017</Value>
<Value>4</Value>
<Value>1</Value>
<Value>1</Value>
<Value>3018</Value>
<Value>4</Value>
<Value>1</Value>
<Value>1</Value>
<Value>3123</Value>
<Value>4</Value>
<Value>3</Value>
<Value>3</Value>
<Value>3124</Value>
<Value>3</Value>
<Value>5</Value>
<Value>5</Value>
<Value>3023</Value>
<Value>8</Value>
<Value>5</Value>
<Value>3</Value>
<Value>3054</Value>
<Value>4</Value>
<Value>1</Value>
<Value>1</Value>
<Value>3055</Value>
<Value>4</Value>
<Value>1</Value>
<Value>1</Value>
<Value>3126</Value>
<Value>8</Value>
<Value>5</Value>
<Value>5</Value>
<Value>3021</Value>
<Value>8</Value>
<Value>3</Value>
<Value>3</Value>
<Value>52</Value>
<Value>10</Value>
<Value>5</Value>
<Value>5</Value>
<Value>85</Value>
<Value>2</Value>
<Value>5</Value>
<Value>5</Value>
<Value>3211</Value>
<Value>2</Value>
<Value>5</Value>
<Value>0</Value>
<Value>3210</Value>
<Value>5</Value>
<Value>0</Value>
<Value>0</Value>
<Value>111</Value>
<Value>5</Value>
<Value>5</Value>
<Value>0</Value>
<Value>103</Value>
<Value>5</Value>
<Value>5</Value>
<Value>1</Value>
<Value>87</Value>
<Value>5</Value>
<Value>3</Value>
<Value>0</Value>
<Value>3236</Value>
<Value>1</Value>
<Value>3</Value>
<Value>0</Value>
</Property>
<Property Id="3074" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>5</Value>
</Property>
<Property Id="3126" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>0</Value>
</Property>
<Property Id="3008" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3009" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>100</Value>
</Property>
<Property Id="3114" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>3</Value>
</Property>
<Property Id="3211" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3011" Tag="BACNET_APPLICATION_TAG_BOOLEAN">
<Value>False</Value>
</Property>
<Property Id="3014" Tag="BACNET_APPLICATION_TAG_DATETIME">
<Value>1/1/0001 12:00:00 AM</Value>
</Property>
<Property Id="3015" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value />
</Property>
<Property Id="3016" Tag="BACNET_APPLICATION_TAG_NULL" />
<Property Id="3019" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value>T=1.1</Value>
</Property>
<Property Id="3017" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>100</Value>
</Property>
<Property Id="3018" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3021" Tag="BACNET_APPLICATION_TAG_ENUMERATED">
<Value>2</Value>
</Property>
<Property Id="3023" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING">
<Value />
</Property>
<Property Id="3054" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0.01</Value>
</Property>
<Property Id="3055" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3210" Tag="BACNET_APPLICATION_TAG_BOOLEAN">
<Value>False</Value>
</Property>
<Property Id="3123" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>0</Value>
</Property>
<Property Id="3124" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3122" Tag="BACNET_APPLICATION_TAG_UNSIGNED_INT">
<Value>2</Value>
</Property>
<Property Id="3212" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0.1</Value>
</Property>
<Property Id="PROP_MAX_PRES_VALUE" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>100</Value>
</Property>
<Property Id="PROP_MIN_PRES_VALUE" Tag="BACNET_APPLICATION_TAG_REAL">
<Value>0</Value>
</Property>
<Property Id="3236" Tag="BACNET_APPLICATION_TAG_BOOLEAN">
<Value>False</Value>
</Property>
<Property Id="3243" Tag="BACNET_APPLICATION_TAG_BOOLEAN">
<Value>False</Value>
</Property>
</Properties>
</Object>
</Objects>
</DeviceStorage>

有多个<Object> </Object>对。我的代码可以得到标签,但不能得到<Value></Value>

里面的值
import xml.etree.ElementTree as ET
xmlfile = 'AS01.xml'
tree = ET.parse(xmlfile)
root = tree.getroot()
lst = tree.findall('Objects/Object/Properties')
for item in lst:
for prop in item:
obj_tag = prop.attrib['Tag']
obj_value = prop.get('Value')
print(obj_tag, obj_value)

对于每个<Object>,我需要TypeInstance的值:

<Object Type="OBJECT_ANALOG_OUTPUT" Instance="5">
OBJECT_ANALOG_OUTPUT
5

和基于属性Id的几个值,例如:

<Property Id="PROP_OBJECT_NAME" Tag="BACNET_APPLICATION_TAG_CHARACTER_STRING"><Value>B'JC2415'DUV'Y1</Value>
PROP_OBJECT_NAME
B'JC2415'DUV'Y1

有什么建议可以解决这个问题吗?编辑:

这就是我解决问题的方法。这句话不好听,但对我有用:

import xml.etree.ElementTree as ET
xmlfile = 'AS01.xml'
tree = ET.parse(xmlfile)
root = tree.getroot()
PROP_OBJECT_IDENTIFIER = ''
PROP_OBJECT_NAME = ''
PROP_DESCRIPTION = ''
BACNET_APPLICATION_TAG_CHARACTER_STRING = ''
def format_string(obj_ident, obj_name,obj_desc,obj_addr):
# Format the recovered values so I can pipe them into CSV files
OBJECT_IDENTIFIER=''
OBJECT_INSTANCE=''
OBJECT_PATH=''
OBJECT_NAME=''
OBJECT_BUS=''
OBJECT_ADDR=''

str_colon = ':'
str_apo = '''
str_eq = '='
if str_colon in obj_ident:                      # Separate Identifier and instance number
cnt = obj_ident.rfind(str_colon)
cntp = cnt+1
OBJECT_IDENTIFIER = obj_ident[0:cnt]
OBJECT_INSTANCE = obj_ident[cntp:]
if str_apo in obj_name:                         # Separate object path and name
cnt = obj_name.rfind(str_apo)
cntp = cnt+1
OBJECT_PATH = obj_name[0:cnt]
OBJECT_NAME = obj_name[cntp:]
if str_eq in obj_addr:                          # Separate address type and the actual addres
cnt = obj_addr.rfind(str_eq)
cntp = cnt+1
OBJECT_BUS = obj_addr[0:cnt]
OBJECT_ADDR = obj_addr[cntp:]
print(OBJECT_IDENTIFIER,',',OBJECT_INSTANCE,',',OBJECT_PATH,',',OBJECT_NAME,',',OBJECT_BUS,',',OBJECT_ADDR,',',obj_desc)

for obj in tree.findall('Objects/Object'):
for prop in obj.findall('Properties/Property'):
obj_id = prop.attrib['Id']
obj_tag = prop.attrib['Tag']

lst = prop.findall('Value')                 # Check for Value field
lst_count = len(lst)                    
if lst_count > 0:                           # If Value field exists
obj_value = prop.find('Value').text
elif lst_count == 0:                        # If Value field is missing
obj_value = ''
if obj_id == 'PROP_OBJECT_IDENTIFIER':      # Select only the necessary objects
PROP_OBJECT_IDENTIFIER = obj_value
if obj_id == 'PROP_OBJECT_NAME':
PROP_OBJECT_NAME = obj_value
if obj_id == 'PROP_DESCRIPTION':
PROP_DESCRIPTION = obj_value
if obj_id == '3019':
BACNET_APPLICATION_TAG_CHARACTER_STRING = obj_value
format_string(PROP_OBJECT_IDENTIFIER,PROP_OBJECT_NAME,PROP_DESCRIPTION,BACNET_APPLICATION_TAG_CHARACTER_STRING)
PROP_OBJECT_IDENTIFIER = ''
PROP_OBJECT_NAME = ''
PROP_DESCRIPTION = ''
BACNET_APPLICATION_TAG_CHARACTER_STRING = ''

输出:

OBJECT_ANALOG_OUTPUT , 5 , B'JC2415'DUV , Y1 , T , 1.1 , Analog out Y1
OBJECT_ANALOG_OUTPUT , 6 , B'JC2415'DUV , Y2 , T , 1.2 , Analog out Y2
OBJECT_ANALOG_OUTPUT , 7 , B'JC2415'PVV , Y1 , T , 1.3 , Analog out Y1
OBJECT_ANALOG_OUTPUT , 8 , B'JC2415'PVV , Y2 , T , 1.4 , Analog out Y2

我不确定我的问题是否正确,但对于值,我会选择:

values = [i.text for i in tree.findall('.//*/Value')]

和"Object"属性:

types=[i.get('Type') for i in tree.findall('.//*Object/[@Type]')]
instances=[i.get('Instance') for i in a.findall('.//*Object/[@Instance]')]