2014-09-25 1 views
2

Я пытаюсь разобрать следующий xml, чтобы вытащить определенные данные, а затем в конечном итоге отредактировать данные по мере необходимости.Python xml parsing etree find element X by post

Вот XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<CHECKLIST> 
<VULN> 
    <STIG_DATA> 
     <VULN_ATTRIBUTE>Vuln_Num</VULN_ATTRIBUTE> 
     <ATTRIBUTE_DATA>V-38438</ATTRIBUTE_DATA> 
    </STIG_DATA> 
    <STIG_DATA> 
     <VULN_ATTRIBUTE>Rule_Title</VULN_ATTRIBUTE> 
     <ATTRIBUTE_DATA>More text.</ATTRIBUTE_DATA> 
    </STIG_DATA> 
    <STIG_DATA> 
     <VULN_ATTRIBUTE>Vuln_Discuss</VULN_ATTRIBUTE> 
     <ATTRIBUTE_DATA>Some text here</ATTRIBUTE_DATA> 
    </STIG_DATA> 
    <STIG_DATA> 
     <VULN_ATTRIBUTE>IA_Controls</VULN_ATTRIBUTE> 
     <ATTRIBUTE_DATA></ATTRIBUTE_DATA> 
    </STIG_DATA> 
    <STIG_DATA> 
     <VULN_ATTRIBUTE>Rule_Ver</VULN_ATTRIBUTE> 
     <ATTRIBUTE_DATA>Gen000000</ATTRIBUTE_DATA> 
    </STIG_DATA> 
    <STATUS>NotAFinding</STATUS> 
    <FINDING_DETAILS></FINDING_DETAILS> 
    <COMMENTS></COMMENTS>   
    <SEVERITY_OVERRIDE></SEVERITY_OVERRIDE> 
    <SEVERITY_JUSTIFICATION></SEVERITY_JUSTIFICATION> 
</VULN> 

Данные, которые я ищу, чтобы вытащить из этого СТАТУС, КОММЕНТАРИИ и ATTRIBUTE_DATA непосредственно после VULN_ATTRIBUTE, что соответствует == Rule_Ver. Итак, в этом примере.

я должен получить следующее: Gen000000 NotAFinding None

То, что я до сих пор, что я могу получить статус и комментарии легко, но не могу понять, часть ATTRIBUTE_DATA. Я могу найти первый (Vuln_Num), затем я попытался добавить индекс, но это дает ошибку «индекс индекса вне диапазона».

Здесь я и сейчас.

import xml.etree.ElementTree as ET 
doc = ET.parse('test.ckl') 
root=doc.getroot() 

TagList = doc.findall("./VULN") 

for curTag in TagList: 
    StatusTag = curTag.find("STATUS") 
    CommentTag = curTag.find("COMMENTS") 
    DataTag = curTag.find("./STIG_DATA/ATTRIBUTE_DATA") 
    print "GEN:[%s] Status:[%s] Comments: %s" %(DataTag.text, StatusTag.text, CommentTag.text) 

Это дает следующий результат: GEN:[V-38438] Status:[NotAFinding] Comments: None

Я хочу: GEN:[Gen000000] Status:[NotAFinding] Comments: None

Поэтому конечной целью является, чтобы иметь возможность анализировать сотни этих и редактировать поле для комментариев, как это необходимо. Я не думаю, что часть редактирования будет такой сложной, как только я получу нужный элемент.

Логически я вижу два способа сделать это. Перейдите в ATTRIBUTE_DATA [5] и возьмите текст или найдите VULN_ATTRIBUTE == Rule_Ver, затем возьмите следующий ATTRIBUTE_DATA.

Я попытался сделать это:

DataTag = curTag.find(".//STIG_DATA//ATTRIBUTE_DATA")[5] and DataTag [5] .text`

и оба дают мне IndexError: list index out of range

Я видел LXML был get_element_by_id и XPath, но я не могу добавить модули к этой системе, так что это для меня.

Заранее спасибо.

ответ

2

Можно найти элемент по положению, но вы использовали неправильный синтаксис XPath. Любая из следующих строк должна работать:

DataTag = curTag.find("./STIG_DATA[5]/ATTRIBUTE_DATA") # Note: 5, not 4 
DataTag = curTag.findall("./STIG_DATA/ATTRIBUTE_DATA")[4] # Note: 4, not 5 

Однако я настоятельно рекомендую не использовать это. Нет гарантии, что Rule_Ver экземпляр STIG_DATA всегда является пятым элементом.

Если бы вы могли изменить в lxml, то это работает:

DataTag = curTag.xpath(
    './STIG_DATA/VULN_ATTRIBUTE[text()="Rule_Ver"]/../ATTRIBUTE_DATA')[0] 

Поскольку вы не можете использовать lxml, вы должны итерировании STIG_DATA элементов вручную, например, так:

def GetData(curTag): 
    for stig in curTag.findall('STIG_DATA'): 
     if stig.find('VULN_ATTRIBUTE').text == 'Rule_Ver': 
      return stig.find('ATTRIBUTE_DATA') 

Здесь представляет собой полную программу с проверкой ошибок, добавленную к GetData():

import xml.etree.ElementTree as ET 
doc = ET.parse('test.ckl') 
root=doc.getroot() 

TagList = doc.findall("./VULN") 

def GetData(curTag): 
    for stig in curTag.findall('STIG_DATA'): 
     vuln = stig.find('VULN_ATTRIBUTE') 
     if vuln is not None and vuln.text == 'Rule_Ver': 
      data = stig.find('ATTRIBUTE_DATA') 
      return data 

for curTag in TagList: 
    StatusTag = curTag.find("STATUS") 
    CommentTag = curTag.find("COMMENTS") 
    DataTag = GetData(curTag) 
    print "GEN:[%s] Status:[%s] Comments: %s" %(DataTag.text, StatusTag.text, CommentTag.text) 

Ссылки:

+0

спасибо за информацию. Функция GetData работает как чемпион. – user3699853