Python ElementTree find () с использованием пространств имен - PullRequest
1 голос
/ 30 апреля 2019

Я пытаюсь использовать ElementTree в Python для анализа и изменения файла XML. Путаница происходит с пространством имен XML. Я могу использовать findall и finditer, чтобы получить все имена серверов. Однако я не могу заставить запрос xpath работать, чтобы найти конкретный сервер. вместо этого find просто возвращает родительский элемент.

Что мне нужно сделать, так это найти правильный сервер по элементу «name» или «machine» и изменить «arguments».

<? xml version=’1.0’ encoding=’UTF-8’?>
<domain xmlns=”http://xmlns.oracle.com.weblogic/domain”>
  <server>
    <name>Server1-rma</name>
    <machine>server1</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server2-rma</name>
    <machine>server2</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server3-rma</name>
    <machine>server3</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
</domain>

Я пытался выполнить различные итерации запроса. Тем не менее, я новичок в XPath и, должно быть, делаю что-то не так:

Ошибка: root + “ns0:server/[ns0:machine=’server2’]

Ошибка: root + “ns0:server/ns0:[machine=’server2’]

Ошибка: root + “ns0:server/[ns0:machine=ns0:’server2’]

пример кода:

import xml.etree.ElementTree as ET
namespace = {‘ns0’: ‘ http://xmlns.oracle.com.weblogic/domain’}

tree = ET.parse(‘config.xml’)
root = tree.getroot()
for item in root.find((root + “ns0:server/[ns0:machine=’server2’]), namespace)
    print(item.tag)


output:
{http://xmlns.oracle.com.weblogic/domain}server

Я надеялся, что смогу сопоставить элемент "machine" и извлечь родительский элемент для доступа к правильному элементу "arguments".

Я новичок в xpath и elementtree, поэтому я уверен, что просто делаю что-то неправильно. Я просто не уверен, что. Любая помощь будет принята с благодарностью.

1 Ответ

1 голос
/ 01 мая 2019

Как и Алехандро, упомянутый в комментарии, ElementTree имеет ограниченную поддержку XPath . Это не должно иметь большого значения для того, что вы пытаетесь сделать. Если вам нужна полная поддержка XPath 1.0, рассмотрите lxml .

Однако, у него есть и другие причуды. Одним из них является то, что он добавит свой собственный префикс пространства имен в ваше пространство имен по умолчанию. Чтобы сохранить пространство имен по умолчанию, вам нужно зарегистрировать его с помощью register_namespace () .

Алехандро также прав, что правильный XPath для выбора сервера будет:

/ns0:domain/ns0:server[ns0:machine='server2']

Однако, когда вы строите дерево (с ET.parse()) или получаете корень (с getroot()), контекст уже равен ns0:domain, поэтому XPath в этом контексте на самом деле будет:

./ns0:server[ns0:machine='server2']

Поскольку вы хотите обновить arguments сервера, мы можем добавить это и в XPath:

./ns0:server[ns0:machine='server2']/ns0:server-start/ns0:arguments

См. Здесь для получения дополнительной информации о путях расположения XPath.

Вот полный пример. (Я использую префикс wl вместо ns0 только для того, чтобы показать, что префикс на самом деле не имеет значения, если он соответствует правилам для пространств имен префиксов.)

XML Input (test.xml; фиксированные кавычки и объявление XML, поэтому оно будет правильно сформировано )

<?xml version='1.0' encoding='UTF-8'?>
<domain xmlns="http://xmlns.oracle.com.weblogic/domain">
  <server>
    <name>Server1-rma</name>
    <machine>server1</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server2-rma</name>
    <machine>server2</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server3-rma</name>
    <machine>server3</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
</domain>

Python

import xml.etree.ElementTree as ET

tree = ET.parse("test.xml")

ns = {"wl": "http://xmlns.oracle.com.weblogic/domain"}

ET.register_namespace("", ns["wl"])

try:
    tree.find("./wl:server[wl:machine='server2']/wl:server-start/wl:arguments", namespaces=ns).text = "BAM!!!"
except AttributeError:
    print("Unable to find the correct server element.")

tree.write("output.xml", xml_declaration=True, encoding="UTF-8")

Вывод XML (output.xml)

<?xml version='1.0' encoding='UTF-8'?>
<domain xmlns="http://xmlns.oracle.com.weblogic/domain">
  <server>
    <name>Server1-rma</name>
    <machine>server1</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
  <server>
    <name>Server2-rma</name>
    <machine>server2</machine>
    <server-start>
      <arguments>BAM!!!</arguments>
    </server-start>
  </server>
  <server>
    <name>Server3-rma</name>
    <machine>server3</machine>
    <server-start>
      <arguments> -Xms4g</arguments>
    </server-start>
  </server>
</domain>
...