Разобрать xsi: введите XML с ElementTree на Python - PullRequest
0 голосов
/ 04 июня 2019

Я пытаюсь подключиться к RESTful API, и у меня возникают проблемы при создании запроса XML, для этого я использую библиотеку Elementree.

У меня есть пример XML, который мне нужноотправьте запрос.Из этого примера создайте модель, а затем запишите различные атрибуты по коду.Но выходной XML не совсем соответствует приведенному мной примеру, и я не могу подключиться к API.

Вот мой пример:

  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
      <GetLoc xmlns="http://abc/Getloc">
        <request>
          <Access>
            <string xmlns="http://bcd/Arrays"></string>
          </Access>
          <Details xsi:type="Request">
            <Postcode ></Postcode >
          </Details>
          <UserConsent>Yes</UserConsent>
        </request>
      </GetLoc>
    </soap:Body>
  </soap:Envelope>

Это мой код:

tree = ET.parse('model.xml')
root = tree.getroot()
ns = {'loc':'http://abc/Getloc',\
        'arr':http://bcd/Arrays',\
        'soapenv':'http://schemas.xmlsoap.org/soap/envelope/', \
        'xsi':"http://www.w3.org/2001/XMLSchema-instance", \
         xsd': "http://www.w3.org/2001/XMLSchema"}

tree.find('.//arr:string', ns).text = 'THC'
tree.find('.//Postcode ', ns).text = '15478'

Это выходной XML (SOAP):

  <ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ns0:Body>
      <ns1:GetLoc >
        <ns1:request>
          <ns1:Access>
            <ns2:string>THC</ns2:string>
          </ns1:Access>
          <ns1:Details xsi:type="Request">
            <ns1:Postcode >15478</ns1:Postcode >
          </ns1:Details>
          <ns1:UserConsent>Yes</ns1:UserConsent>
        </ns1:request>
      </ns1:GetLoc >
    </ns0:Body>
  </ns0:Envelope>

С примером (первым выше) у меня нет проблем при подключении к API.Однако со вторым я получаю и ошибку:

 " status="Service Not Found.  The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/>"

Оба XML отправляются на один и тот же URL с одинаковыми заголовками и аутентификацией.Я вижу оба XML-эквивалента, поэтому я ожидал того же поведения.Я не понимаю, почему это не работает.

РЕДАКТИРОВАТЬ: выходной XML должен быть похож на

<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <ns0:Body>
          <ns1:GetLoc >
            <ns1:request>
              <ns1:Access>
                <ns2:string>THC</ns2:string>
              </ns1:Access>
              <ns1:Details xsi:type="ns1:Request">
                <ns1:Postcode >15478</ns1:Postcode >
              </ns1:Details>
              <ns1:UserConsent>Yes</ns1:UserConsent>
            </ns1:request>
          </ns1:GetLoc >
        </ns0:Body>
      </ns0:Envelope>

Но я не знаю, как изменить код, чтобы получить: xsi: type = "ns1: Request"

1 Ответ

0 голосов
/ 04 июня 2019

Наконец-то я сам нашел решение.

Решение находится в здесь (невероятно полная статья), так как я уже использовал ElementTree. Вы можете найти другие решения, такие как использование библиотеки lxml .

Итак, для ElementTree мне просто нужно использовать собственный синтаксический анализатор вместо стандартного ElementTree.parse ('file.xml') .

Имя атрибута xsi обрабатывается анализатором, но синтаксический анализатор не знает, что атрибут содержит также определенное имя, поэтому оставляет его как есть. Чтобы иметь возможность обрабатывать такой формат, вы можете использовать собственный анализатор, который знает, как обрабатывать определенные атрибуты и элементы, или отслеживать отображение префикса для каждого элемента. Для этого вы можете использовать синтаксический анализатор iterparse и попросить его сообщать о событиях «start-ns» и «end-ns». Следующий фрагмент добавляет атрибут ns_map к каждому элементу, который содержит префикс / сопоставление URI, которое применяется к этому конкретному элементу:

def parse_map(file):
    events = "start", "start-ns", "end-ns"
    root = None
    ns_map = []
    for event, elem in ET.iterparse(file, events):
        if event == "start-ns":
            ns_map.append(elem)
        elif event == "end-ns":
            ns_map.pop()
        elif event == "start":
            if root is None:
                root = elem
            elem.ns_map = dict(ns_map)
    return ET.ElementTree(root)
...