【问题标题】:Setting values without pytype - lxml objectify在没有 pytype 的情况下设置值 - lxml objectify
【发布时间】:2018-03-25 17:40:10
【问题描述】:

使用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>

有一些解决方案可以在创建元素后使用deannotate() 函数(例如When using lxml, can the XML be rendered without namespace attributes?Remove "xmlns:py..." with lxml.objectify)删除pytype 及其命名空间。没有任何解决方案可以从一开始就创建没有pytype 及其命名空间的元素。关于如何做到这一点的任何想法?

【问题讨论】:

    标签: python lxml lxml.objectify


    【解决方案1】:

    lxml.objectify 中,有两种元素:由Element 工厂创建的树元素和由DataElement 工厂或特定数据类创建的数据元素,例如StringElementIntElement(有关更多信息,请参阅 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>
    

    【讨论】:

    • 剧透警告!! JK,谢谢 :) 在我的情况下,我想将一个字符串添加到一个属性中并且得到了 attribute pytype is not allowed 错误。用objectify.DataElement(&lt;YOUR_STRING&gt;, _pytype='') 替换字符串赋值就可以了
    【解决方案2】:

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

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

    也就是说:只要不改变值类型就可以使用。

    【讨论】:

    • 您能进一步解释一下吗?
    • @Abayomi Israel 我试图在上面更好地解释它
    猜你喜欢
    • 2023-03-04
    • 2021-03-20
    • 2014-01-07
    • 1970-01-01
    • 2021-10-27
    • 2018-02-04
    • 2014-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多