python - 对于python 3,使用lxml在属性前面写入 'xsi:'

标签 python xml python-3.x lxml

我正在向 xml 文件添加元素。

文档的根目录如下

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

要添加的元素看起来像

<Element xsi:type="some type">
  <Sub1>Some text</Sub1>
  <Sub2>More text</Sub2>
  ...
</Element>

我正在尝试找到一种方法让 lxml 在我的元素属性前面写入“xsi:”。该 xml 文件由我无权访问其源代码的程序使用。我在其他几个问题中读到了如何通过声明 xml 根的 nsmap 来做到这一点,然后在子属性中再次声明,我尝试过但它不起作用。到目前为止我已经(这不起作用,输出文件不包含 xsi 前缀):

element = SubElement(_parent=parent, 
                     _tag='some tag', 
                     attrib={'{%s}type' % XSI: 'some type'}
                     nsmap={'xsi': XSI})  # Where XSI = namespace address

命名空间在我解析的 xml 文件中正确声明,所以我不知道为什么这不起作用。 我得到的输出是如上所示的元素,没有“xsi:”前缀,并且全部在一行上:

<Element type="some type"><Sub1>Some text</Sub1><Sub2>More text</Sub2>...</Element>

如果有人也能指出这一行的原因

self.tree.write(self.filename, pretty_print=True, encoding='utf-8')

“pretty_print”选项不起作用(全部打印在一行中),我们将不胜感激。

这是我的脚本的代码示例:

from math import floor
from lxml import etree
from lxml.etree import SubElement


def Element(root, sub1: str):
    if not isinstance(sub1, str):
        raise TypeError
    else:
        element = SubElement(root, 'Element')
        element_sub1 = SubElement(element, 'Sub1')
        element_sub1.text = sub1
        # ...
        # Omitted additional SubElements
        # ...
        return element


def Sub(root, sub5_sub: str):
    XSI = "http://www.w3.org/2001/XMLSchema-instance"
    if not isinstance(sub5_sub, str):
        raise TypeError
    else:
        sub = SubElement(root, 'Sub5_Sub', {'{%s}type' % XSI: 'SomeType'}, nsmap={'xsi': XSI})
        # ...
        # Omitted additional SubElements
        # ...
        return sub


class Generator:
    def __init__(self) -> None:
        self.filename = None
        self.csv_filename = None
        self.csv_content = []
        self.tree = None
        self.root = None
        self.panel = None
        self.panels = None

    def mainloop(self) -> None:
        """App's mainloop"""
        while True:
            # Getting files from user
            xml_filename = input('Enter path to xml file : ')

            # Parsing files
            csv_content = [{'field1': 'ElementSub1', 'field2': 'something'},
                           {'field1': 'ElementSub1', 'field2': 'something'},
                           {'field1': 'ElementSub2', 'field2': 'something'}]  # Replaces csv file that I use
            tree = etree.parse(xml_filename)
            root = tree.getroot()

            elements = root.find('Elements')

            for element in elements:
                if element.find('Sub1').text in ['ElementSub1', 'ElementSub2']:
                    for line in csv_content:
                        if element.find('Sub5') is not None:
                            Sub(root=element.find('Sub5'),
                                sub5_sub=line['field2'])

            tree.write(xml_filename, pretty_print=True, encoding='utf-8')

            if input('Continue? (Y) Quit (n)').upper().startswith('Y'):
                elements.clear()
                continue
            else:
                break

    @staticmethod
    def get_x(x: int) -> str:
        if not isinstance(x, int):
            x = int(x)
        return str(int(floor(9999 / 9 * x)))

    @staticmethod
    def get_y(y: int) -> str:
        if not isinstance(y, int):
            y = int(y)
        return str(int(floor(999 / 9 * y)))

    def quit(self) -> None:
        quit()


if __name__ == "__main__":
    app = Generator()
    app.mainloop()
    app.quit()

这是它的输出:

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Elements>
    <Element>
      <Sub1>ElementSub1</Sub1>
      <Sub5>
        <Sub5_Sub xsi:type="SomeType"/>
      <Sub5_Sub xsi:type="SomeType"/><Sub5_Sub xsi:type="SomeType"/><Sub5_Sub xsi:type="SomeType"/></Sub5>
    </Element>
    <Element>
      <Sub1>ElementSub1</Sub1>
      <Sub5>
        <Sub5_Sub xsi:type="SomeType"/>
        <Sub5_Sub xsi:type="SomeType"/>
      <Sub5_Sub xsi:type="SomeType"/><Sub5_Sub xsi:type="SomeType"/><Sub5_Sub xsi:type="SomeType"/></Sub5>
    </Element>
    <Element>
      <Sub1>ElementSub1</Sub1>
    </Element>
  </Elements>
</Root>

出于某种原因,这段代码可以实现我想要的功能,但我的真实代码却不能。我开始意识到它确实在一些具有 type 属性的子元素上添加了前缀,但不是所有子元素,并且在它添加前缀的子元素上,它并不总是只是“xsi:”。我找到了一种快速而肮脏的方法来解决这个问题,这种方法不太理想(通过 xsi-type 文件查找并替换 -> 由 lxml 的 api 接受为 xsi:type)。但仍然不起作用的是,尽管 Pretty_print 参数为 true,但它还是在一行中全部打印出来。

最佳答案

我最近遇到了这种情况,并且能够使用 xsi: 成功创建属性

qname = etree.QName("http://www.w3.org/2001/XMLSchema-instance", "type")
element = etree.Element('Element', {qname: "some type")

root.append(element)

这会输出类似的内容

<Element xsi:type="some type">

关于python - 对于python 3,使用lxml在属性前面写入 'xsi:',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47399807/

相关文章:

python - 在 Python 中通过套接字在两个进程之间传递共享内存对象

java - Firebase - 当数据根据用户记录更新时如何使适配器逻辑

python - 如何一次计算所有每个 numpy 值的概率?

linux - ipsec 在 archlinux 下验证时出现 python 错误

python - 如何在 SQLAlchemy/Postgres 中限制每个 `group_by` 的 N 个结果?

python - 用于通讯python的UNIX套接字-C++

Python ctypes : SetWindowsHookEx callback function never called

xml - XSD 模式是否可以根据是否存在多个元素而具有不同的条件?

asp.net - 如何隐藏复选框列表中未选中的项目?

python - 如何使用Python的Request包访问API Get的特定元素?