3

objectify使用库的API 为元素设置值,默认情况下lxml将自动检测分配pytype给该元素和所需的命名空间。

例如,设置根元素:

root = objectify.Element('root')
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

输出:

<root xmlns:py="http://codespeak.net/lxml/objectify/pytype"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="TREE"/>

或为子元素设置值:

child = objectify.SubElement(root, 'child')
root.child = 'value'
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

输出:

<root xmlns:py="http://codespeak.net/lxml/objectify/pytype"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="TREE">
  <child py:pytype="str">value</child>
</root>

即使使用 ObjectPath 的 setattr:

path = objectify.ObjectPath('root.vader.son')
path.setattr(root, 'Luke')
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

输出:

<root xmlns:py="http://codespeak.net/lxml/objectify/pytype"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" py:pytype="TREE">
  <child py:pytype="str">value</child>
  <vader>
    <son py:pytype="str">Luke</son>
  </vader>
</root>

有一些解决方案可以在创建元素后使用该函数删除pytype及其命名空间(例如,使用 lxml 时,是否可以在没有命名空间属性的情况下呈现 XML?,使用 lxml.objectify 删除“xmlns:py ...”)。没有任何解决方案可以从一开始就创建没有 the 及其名称空间的元素。关于如何做到这一点的任何想法?deannotate()pytype

4

2 回答 2

3

lxml.objectify中,有两种元素:由工厂创建的树元素Element和由工厂或特定数据类创建的数据元素,DataElement例如StringElementIntElement(有关更多信息,请参阅此处)。一种解决方案可能是清空_pytype特定元素的命名空间和参数,方法是将其分配给空字符串,并且从不使用文字的直接分配。要从文字创建元素,您必须使用 DataElement 工厂。请注意,如果您有任何特定的命名空间,则必须将命名空间映射而不是空字符串分配给 nsmap 参数。不过有一个问题。如果你想创建一个树元素,设置nsmap_pytype对于空字符串,命名空间和 pytype 不会被删除。我不知道为什么。所以这个解决方案只适用于数据元素。

这是您尝试构建的树的代码:

root = objectify.Element('root', nsmap='', _pytype='')
# sub elements do not need nsmap or _pytype to be emptied
child = objectify.SubElement(root, 'child')
root.child = objectify.DataElement('value', nsmap='', _pytype='')
path = objectify.ObjectPath('root.vader.son')
path.setattr(root, objectify.DataElement('Luke', nsmap='', _pytype=''))
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

哪个输出:

<root xmlns:py="http://codespeak.net/lxml/objectify/pytype" py:pytype="">
  <child>value</child>
  <vader>
    <son>Luke</son>
  </vader>
</root>

不是我们想要的!

解决方案在于使用ElementMaker工厂的解决方法。

# Create your ElementMaker factory, without annotations.
E = objectify.ElementMaker(annotate=False)
# If you have any namespaces you want to use, assign them to the nsmap
# parameter and assign the default namespace to the namespace parameter.
# E = objectify.ElementMaker(annotate=False, namespace=namespace, nsmap=nsmap)
root = E.root()
print(etree.tostring(root, pretty_print=True))

这输出:

<root/>

引入树元素的命名空间和 pytype 问题已得到解决。现在我们可以分配子元素或数据元素:

objectify.SubElement(root, 'child')
root.child = objectify.DataElement('value', nsmap='', _pytype='')
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

输出:

<root>
  <child>value</child>
</root>

使用该方法的一个例子setattr()是:

root = E.root()
path = objectify.ObjectPath('root.vader.son')
path.setattr(root, objectify.DataElement('Luke', nsmap='', _pytype=''))
# mysteriously, the below line works the same as the above line:
# path.setattr(root, E.whatevername('Luke'))
print(etree.tostring(root, pretty_print=True).decode('utf-8'))

其输出是:

<root>
  <vader>
    <son>Luke</son>
  </vader>
</root>
于 2018-03-25T17:40:10.103 回答
1

另一种解决方法可能会对您有所帮助:在设置元素时,您可以使用_setText()方法: vader.son._setText('Luke')

原因:基于“lxml.objectify.ObjectifiedElement”的“class lxml.objectify.ObjectifiedDataElement”有一个私有方法_setText()。此方法专用于仅在子类中使用,即 lxml.objectify.StringElement-class 并且不影响 pytype https://lxml.de/apidoc/lxml.objectify.html

换句话说:只要不更改值类型,就可以使用它。

于 2021-06-17T13:50:23.070 回答