在没有 pytype 的情况下设置值 - lxml objectify
Setting values without pytype - lxml objectify
使用 lxml
库的 objectify
API 为元素设置值,默认情况下将自动检测到的 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
及其命名空间,使用 deannotate()
函数(例如 When using lxml, can the XML be rendered without namespace attributes?, Remove "xmlns:py..." with lxml.objectify)。没有任何解决方案可以从一开始就创建没有 pytype
及其名称空间的元素。关于如何做到这一点有什么想法吗?
在lxml.objectify
中有两种元素:由Element
工厂创建的树元素和由DataElement
工厂或特定数据创建的数据元素类,例如 StringElement
、IntElement
(有关详细信息,请参阅 here)。一个解决方案可能是清空命名空间和特定元素的 _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>
另一种解决方法可能对您有所帮助:
设置元素时,可以使用 _setText() 方法:
vader.son._setText('Luke')
原因:
'class lxml.objectify.ObjectifiedDataElement',它基于'lxml.objectify.ObjectifiedElement'有一个私有方法_setText()。
此方法专用于 subclasses,即。 e. lxml.objectify.StringElement-class 并且不影响 pytype
https://lxml.de/apidoc/lxml.objectify.html
也就是说:只要不改变值类型就可以使用
使用 lxml
库的 objectify
API 为元素设置值,默认情况下将自动检测到的 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
及其命名空间,使用 deannotate()
函数(例如 When using lxml, can the XML be rendered without namespace attributes?, Remove "xmlns:py..." with lxml.objectify)。没有任何解决方案可以从一开始就创建没有 pytype
及其名称空间的元素。关于如何做到这一点有什么想法吗?
在lxml.objectify
中有两种元素:由Element
工厂创建的树元素和由DataElement
工厂或特定数据创建的数据元素类,例如 StringElement
、IntElement
(有关详细信息,请参阅 here)。一个解决方案可能是清空命名空间和特定元素的 _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>
另一种解决方法可能对您有所帮助: 设置元素时,可以使用 _setText() 方法: vader.son._setText('Luke')
原因: 'class lxml.objectify.ObjectifiedDataElement',它基于'lxml.objectify.ObjectifiedElement'有一个私有方法_setText()。 此方法专用于 subclasses,即。 e. lxml.objectify.StringElement-class 并且不影响 pytype https://lxml.de/apidoc/lxml.objectify.html
也就是说:只要不改变值类型就可以使用