Python LXML, как я могу использовать тег в названии элементов? - PullRequest
0 голосов
/ 27 сентября 2019

Мне нужно создать XML-файл, используя специальное имя элементов, это мой текущий код:

from lxml import etree
import lxml
from lxml.builder import E

wp = E.wp

tmp = wp("title")

print(etree.tostring(tmp))

текущий вывод такой:

b'<wp>title</wp>'

Я хочу быть:

b'<wp:title>title</title:wp>'

как я могу создавать предметы с таким именем: wp:title?

1 Ответ

2 голосов
/ 27 сентября 2019

Вы перепутали префикс пространства имен wp с именем тега.Префикс пространства имен - это локальное имя документа для URI пространства имен.wp:title требует, чтобы синтаксический анализатор искал атрибут xmlns:wp="..." для поиска самого пространства имен (обычно это URL, но подойдет любая глобально уникальная строка), либо в самом теге, либо в родительском теге.Это соединяет теги с уникальным значением, не делая имен тегов слишком многословными для ввода или чтения.

Вам необходимо предоставить пространство имен и, необязательно, отображение пространства имен (сопоставление коротких имен с полными именами пространства имен) с элементомсоздатель объекта.Предоставленный объект E по умолчанию не имеет установленной карты пространства имен или пространства имен.Я собираюсь предположить, что здесь wp является http://wordpress.org/export/1.2/ пространством имен Wordpress, поскольку это кажется наиболее вероятным, хотя может также случиться так, что вы пытаетесь отправить уведомления Windows Phone .

Вместо использования создателя элемента E по умолчанию создайте свой собственный экземпляр ElementMaker и передайте ему аргумент namespace, чтобы сообщить lxml, к какому URL принадлежит элемент.Чтобы получить правильный префикс для имен ваших элементов, вам также нужно предоставить ему словарь nsmap, который сопоставляет префиксы с URL-адресами:

from lxml.builder import ElementMaker

namespaces = {"wp": "http://wordpress.org/export/1.2/"}
E = ElementMaker(namespace=namespaces["wp"], nsmap=namespaces)

title = E.title("Value of the wp:title tag")

. При этом создается тег с правильным префиксом, и атрибут xmlns:wp:

>>> from lxml.builder import ElementMaker
>>> namespaces = {"wp": "http://wordpress.org/export/1.2/"}
>>> E = ElementMaker(namespace=namespaces["wp"], nsmap=namespaces)
>>> title = E.title("Value of the wp:title tag")
>>> etree.tostring(title, encoding="unicode")
'<wp:title xmlns:wp="http://wordpress.org/export/1.2/">Value of the wp:title tag</wp:title>'

Вы можете опустить значение nsmap, но тогда вы захотите иметь такую ​​карту в элементе parent элементадокумент.В этом случае вы, вероятно, захотите создать отдельные ElementMaker объекты для каждого пространства имен, которое вам нужно поддерживать, и вы поместите отображение пространства имен nsmap на самый внешний элемент.При записи документа lxml затем использует короткие имена повсюду.

Например, для создания документа в формате Wordpress WXR потребуется несколько пространств имен:

from lxml.builder import ElementMaker

namespaces = {
    "excerpt": "https://wordpress.org/export/1.2/excerpt/",
    "content": "http://purl.org/rss/1.0/modules/content/",
    "wfw": "http://wellformedweb.org/CommentAPI/",
    "dc": "http://purl.org/dc/elements/1.1/",
    "wp": "https://wordpress.org/export/1.2/",
}

RootElement = ElementMaker(nsmap=namespaces)
ExcerptElement = ElementMaker(namespace=namespaces["excerpt"])
ContentElement = ElementMaker(namespace=namespaces["content"])
CommentElement = ElementMaker(namespace=namespaces["wfw"])
DublinCoreElement = ElementMaker(namespace=namespaces["dc"])
ExportElement = ElementMaker(namespace=namespaces["wp"])

, а затем вы создадите документ с

doc = RootElement.rss(
    RootElement.channel(
        ExportElement.wxr_version("1.2"),
        # etc. ...
    ),
    version="2.0"
)

, который, при печати с etree.tostring(doc, pretty_print=True, encoding="unicode"), выдаст:

<rss xmlns:excerpt="https://wordpress.org/export/1.2/excerpt/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:wp="https://wordpress.org/export/1.2/" version="2.0">
  <channel>
    <wp:wxr_version>1.2</wp:wxr_version>
  </channel>
</rss>

Обратите внимание, что только корень <rss>Элемент имеет атрибуты xmlns и то, как тег <wp:wxr_version> использует правильный префикс, хотя мы дали ему только URI пространства имен.

Чтобы привести другой пример, если вы создаете уведомление для плитки Windows Phone,было бы проще.В конце концов, нужно использовать только одно пространство имен:

from lxml.builder import ElementMaker

namespaces = {"wp": "WPNotification"}
E = ElementMaker(namespace=namespaces["wp"], nsmap=namespaces)

notification = E.Notification(
    E.Tile(
        E.BackgroundImage("https://example.com/someimage.png"),
        E.Count("42"),
        E.Title("The notification title"),
        # ...
    )
)

, которое создает

<wp:Notification xmlns:wp="WPNotification">
  <wp:Tile>
    <wp:BackgroundImage>https://example.com/someimage.png</wp:BackgroundImage>
    <wp:Count>42</wp:Count>
    <wp:Title>The notification title</wp:Title>
  </wp:Tile>
</wp:Notification>

Только самый внешний элемент, <wp:Notification>, теперь имеет атрибут xmlns:wp,Все остальные элементы должны включать только префикс wp:.

Обратите внимание, что префикс полностью зависит от вас и даже необязательно .Именно URI пространства имен является реальным ключом для уникальной идентификации элементов в разных документах XML.Если вы вместо этого использовали E = ElementMaker(namespace="WPNotification", nsmap={None: "WPNotification"}) и сгенерировали элемент верхнего уровня с <Notification xmlns="WPNotification">, у вас все еще есть совершенно законный документ XML, который, согласно стандарту XML, имеет точно такое же значение.

...