Как настроить пространства имен для Azure tts (mstts) - PullRequest
0 голосов
/ 11 октября 2019

Мне нужно создать этот заголовок для Azure TTS:

 <speak version="1.0" 
  xmlns="https://www.w3.org/2001/10/synthesis" 
   xmlns:mstts="https://www.w3.org/2001/mstts" 
   xml:lang="en-US">

Это код, который работает для создания ключа xml: lang:

xml_body = ElementTree.Element('speak', version='1.0')
xml_body.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-us')

Я пыталсясоздать xmlns: mstts без успеха. Это не работает:

xml_body.set('{https://www.w3.org/2001/10/synthesis}mstts', 'https://www.w3.org/2001/mstts' )

, поскольку это приводит к следующему выводу:

<speak
 xmlns:ns0="https://www.w3.org/2001/10/synthesis"
 version="1.0"
 xml:lang="en-us"
 ns0:mstts="https://www.w3.org/2001/mstts" />

Обратите внимание на проблемы xmlns:ns0 и ns0:mstts в атрибутах элемента <speak>.

Есть идеи?

1 Ответ

2 голосов
/ 11 октября 2019

Вам нужно дать элементу speak пространство имен, а также его атрибут version, который обычно настраивается атрибутом xmlns="...". Используйте для этого * квалифицированный формат имени {<namespaceuri>}<tagname>, как и для атрибута xml:lang:

xml_body = ElementTree.Element('{https://www.w3.org/2001/10/synthesis}speak')
xml_body.set('{https://www.w3.org/2001/10/synthesis}version', '1.0')
xml_body.set('{http://www.w3.org/XML/1998/namespace}lang', 'en-us')

Вы также можете добавить атрибуты в виде словаря, передаваемого в качестве второго аргумента:

xml_body = ElementTree.Element(
    '{https://www.w3.org/2001/10/synthesis}speak', {
        '{https://www.w3.org/2001/10/synthesis}version': '1.0',
        '{http://www.w3.org/XML/1998/namespace}lang': 'en-us'
    })

Вы не должны установить атрибут xmlns:mstts, однако! ElementTree добавит этот атрибут автоматически , если необходимо, в зависимости от того, какие пространства имен были использованы в построенном вами дереве XML.

Вы do хотите зарегистрироваться это пространство имен с ElementTree с использованием функции register_namespace() :

ElementTree.register_namespace('mstts', 'https://www.w3.org/2001/mstts')

Это сообщает ElementTree, что при использовании пространства имен {https://www.w3.org/2001/mstts} с именами тегов или атрибутами, это при сериализации дерева XML в файл или строку , что это пространство имен должно использовать mstts в качестве префикса. Если вы не зарегистрируете пространство имен, для вас будет сгенерирован префикс пространства имен (ns0:, ns1: и т. Д.). Это приведет к совершенно правильному XML, префиксы пространства имен будут локальными для документации, а префиксы - это просто сокращенные имена для полного URI пространства имен. Любой совместимый синтаксический анализатор XML будет обрабатывать ns0 в качестве префикса для URI пространства имен https://www.w3.org/2001/mstts точно так же, как при использовании mstts.

Для пространства имен по умолчанию (например, * 1044). * пространство имен для корневого <speak> элемента), используйте аргумент default_namespace для ElementTree.write() метода .

Мне легче QName() объектов обрабатывать имена пространственных атрибутов и тегов;вместе с переменными для конкретных пространств имен, что снижает вероятность опечаток. Вот более полный пример , основанный на примере из документации Azure SSML

from xml.etree import ElementTree as ET
from functools import partial

ns = {
    "synthesis": "https://www.w3.org/2001/10/synthesis",
    "mstts": "https://www.w3.org/2001/mstts",
    "xml": "http://www.w3.org/XML/1998/namespace",
}
ET.register_namespace('mstts', ns['mstts'])

synthesis = partial(ET.QName, ns["synthesis"])
mstts = partial(ET.QName, ns["mstts"])
xml_ = partial(ET.QName, ns["xml"])

xml_body = ET.Element(synthesis('speak'), {
    synthesis('version'): '1.0',
    xml_('lang'): 'en-us',
})
voice = ET.SubElement(xml_body, synthesis('voice'), {
    synthesis('name'): 'en-US-JessaNeural'})
express_as = ET.SubElement(voice, mstts('express-as'), {
    mstts('type'): 'cheerful'})
express_as.text = "That'd be just amazing!"

root = ET.ElementTree(xml_body)
root.write("filename.xml", encoding="UTF-8", default_namespace=ns["synthesis"])

Приведенный выше код дает следующий XML-код (напечатанный вручную для удобства чтения):

<speak
 xmlns="https://www.w3.org/2001/10/synthesis"
 xmlns:mstts="https://www.w3.org/2001/mstts"
 version="1.0"
 xml:lang="en-us">
    <voice name="en-US-JessaNeural">
        <mstts:express-as mstts:type="cheerful">
            That'd be just amazing!
        </mstts:express-as>
    </voice>
</speak>

Вместо этого вы можете захотеть взглянуть и на external lxml library , так как он включает lxml.builder.ElementMaker class , который делает работу с пространствами имен еще проще,

lxml имеет гораздо лучшую поддержку пространства имен в целом, и атрибуты элемента, у которого уже есть пространство имен, не должны быть явно определены самим пространством имен. Вы можете пометить данное сопоставление пространства имен как значение по умолчанию, используя префикс None в словаре, устанавливающем пространства имен:

from lxml import etree as ET
from lxml.builder import ElementMaker

ns = {
    None: "https://www.w3.org/2001/10/synthesis",
    "mstts": "https://www.w3.org/2001/mstts",
}

E = ElementMaker(namespace=ns[None], nsmap=ns)
TTS = ElementMaker(namespace=ns['mstts'])

xml_body = E.speak(
    {"version": "1.0",
     "{http://www.w3.org/XML/1998/namespace}lang": "en-US"},
    E.voice(
        {"name": "en-US-JessaNeural"},
        TTS('express_as',
            "That'd be just amazing!",
            type="cheerful",
        )
    )
)

. В приведенном выше примере использование E.tagname(...) или E('tagname', ...) создастэлемент с URI пространства имен https://www.w3.org/2001/10/synthesis, а объект MSTTS создает теги с URI пространства имен https://www.w3.org/2001/mstts. Поскольку мы дали E карту пространства имен с None отображением на https://www.w3.org/2001/10/synthesis URI пространства имен, этот URI будет использоваться в качестве пространства имен по умолчанию, а теги и атрибуты в этом пространстве имен не будут иметь префикса.

Выможет передавать атрибуты либо в качестве аргументов ключевого слова (E.tagname(..., attributename="value")), либо через словарь, передаваемый в качестве позиционного аргумента. Любые содержащиеся элементы могут быть просто добавлены в качестве позиционных аргументов, включая текст. Вы также можете добавить обычные Element методы (например, Element.append(), чтобы добавить дочерний элемент, или Element.text = ..., чтобы указать, что такое текстовое содержимое тега).

Демонстрация с использованием lxml:

>>> from lxml import etree as ET
>>> from lxml.builder import ElementMaker
>>> ns = {
...     None: "https://www.w3.org/2001/10/synthesis",
...     "mstts": "https://www.w3.org/2001/mstts",
... }
>>> E = ElementMaker(namespace=ns[None], nsmap=ns)
>>> TTS = ElementMaker(namespace=ns['mstts'])
>>> xml_body = E.speak(
...     {"version": "1.0",
...      "{http://www.w3.org/XML/1998/namespace}lang": "en-US"},
...     E.voice(
...         {"name": "en-US-JessaNeural"},
...         TTS('express_as',
...             "That'd be just amazing!",
...             type="cheerful",
...         )
...     )
... )
>>> print(ET.tostring(xml_body, encoding="unicode", pretty_print=True))
<speak xmlns="https://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" version="1.0" xml:lang="en-US">
  <voice name="en-US-JessaNeural">
    <mstts:express_as type="cheerful">That'd be just amazing!</mstts:express_as>
  </voice>
</speak>
...