Python: создайте разные пути / деревья из XML-файла

#python #xml #path #elementtree

#python #xml #путь #elementtree

Вопрос:

Вот пример XML-файла :

 <?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header />
  <SOAP-ENV:Body>
    <ADD_LandIndex_001>
      <CNTROLAREA>
        <BSR>
          <status>ADD</status>
          <NOUN>LandIndex</NOUN>
          <REVISION>001</REVISION>
        </BSR>
      </CNTROLAREA>
      <DATAAREA>
        <LandIndex>
          <reportId>AMI100031</reportId>
          <requestKey>R3278458</requestKey>
          <SubmittedBy>EN4871</SubmittedBy>
          <submittedOn>2015/01/06 4:20:11 PM</submittedOn>
          <LandIndex>
            <agreementdetail>
              <agreementid>001       4860</agreementid>
              <agreementtype>NATURAL GAS</agreementtype>
              <currentstatus>
                <status>ACTIVE</status>
                <statuseffectivedate>1965/02/18</statuseffectivedate>
                <termdate>1965/02/18</termdate>
              </currentstatus>
              <designatedrepresentative>
              </designatedrepresentative>
            </agreementdetail>
          </LandIndex>
        </LandIndex>
      </DATAAREA>
    </ADD_LandIndex_001>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  

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

 ['Envelope/Body/ADD_LandIndex_01/CNTROLAREA/BSR/status', 'Envelope/Body/ADD_LandIndex_01/CNTROLAREA/BSR/LandIndex', ...]
  

Я пробую небольшой код, который не работает. Я не вижу, как взять отдельно последние элементы одной ветки и как пройти весь путь с самого начала, когда я переключаю узел посередине (т.е Envelope/Body/ADD_LandIndex_01/DATAAREA...

 import xml.etree.ElementTree as et
import os
import pandas as pd
from re import search

filename = 'file_try.xml'
element_tree = et.parse(filename)
root = element_tree.getroot()
namespace = "{http://schemas.xmlsoap.org/soap/envelope/}"


def remove_namespace(string,namespace) :
    
    if search(namespace, string) :
        new_string = string.replace(namespace,'')
    else : 
        new_string= string
    return new_string

dico = {}
title = root.tag
print(title)

for element in root.findall('.//') :
    #print(element)
    if len(list(element)) > 0 :
        #print('True ') 
        title= remove_namespace(title   '/'   element.tag, namespace)
        print(title  'n')

    else :
        
        title = root.tag
  

Кто-нибудь может мне помочь?

Спасибо

Ответ №1:

Вы можете изменить это для вашего фактического кода, но в основном — это должно выглядеть так:

 from lxml import etree
soap = """[your xml above]"""
root = etree.XML(soap.encode())    
tree = etree.ElementTree(root)
for target in root.xpath('//text()'):
    if len(target.strip())>0:       
        print(tree.getpath(target.getparent()).replace('SOAP-ENV:',''))
  

Вывод:

 /Envelope/Body/ADD_LandIndex_001/CNTROLAREA/BSR/status
/Envelope/Body/ADD_LandIndex_001/CNTROLAREA/BSR/NOUN
/Envelope/Body/ADD_LandIndex_001/CNTROLAREA/BSR/REVISION
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/reportId
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/requestKey
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/SubmittedBy
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/submittedOn
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/LandIndex/agreementdetail/agreementid
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/LandIndex/agreementdetail/agreementtype
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/LandIndex/agreementdetail/currentstatus/status
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/LandIndex/agreementdetail/currentstatus/statuseffectivedate
/Envelope/Body/ADD_LandIndex_001/DATAAREA/LandIndex/LandIndex/agreementdetail/currentstatus/termdate
  

Комментарии:

1. Спасибо @Jack Fleeting за ваш ответ, это мне очень помогает, хотелось бы, чтобы у меня были ваши навыки! Как вы импортируете данные из XML-файла в каталог для своей переменной ‘soap’?

2. Извините, я только что нашел, как это сделать с : with open(filename, 'r') as f: soap = f.read()

3. Как вы видели, я сделал предыдущий пост об этом, я хотел бы иметь теперь другой список, который получает текст / содержимое этих путей (элементов). Я не могу найти способ сделать это с помощью этой библиотеки lxml, я попробовал .text() или text_content()`но я получаю сообщение об ошибке: цель состоит в том, чтобы иметь это в фрейме данных для экспорта в Excel. Что такое функция или строка для получения содержимого? Код : for target in root.xpath('//text()'): if len(target.strip())>0: path = tree.getpath(target.getparent()).replace('SOAP-ENV:','') data = target.text() mylist_path.append(path)

4. @Maikiii Рад, что это сработало для вас! Что касается другого, политика переполнения стека гласит, что вы должны опубликовать это как отдельный вопрос.

5. @ Jack, спасибо за информацию, я переделываю новый qpost