0

使用 PyXB,我想序列化一个子节点,然后能够将其解析回来。天真的方法行不通,因为根据架构,子节点不是有效的根元素。

我的架构:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="root" type="Root"/>

  <xsd:complexType name="Root">
    <xsd:sequence>
      <xsd:element name="item" maxOccurs="unbounded" type="Item"/>
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="Item">
    <xsd:sequence>
      <xsd:element name="val"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

和示例 XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
    <item>
        <val>1</val>
    </item>
    <item>
        <val>2</val>
    </item>
    <item>
        <val>3</val>
    </item>
</root>

我需要能够序列化特定项目,然后将其加载回来。像这样的东西:

>>> root = CreateFromDocument(sample)
# locate a sub node to serialize
>>> root.item[1].toxml()
'<?xml version="1.0" ?><item><val>2</val></item>'
# load the sub node, getting an Item back
>>> sub_node = CreateFromDocument('<?xml version="1.0" ?><item><val>2</val></item>')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "binding.py", line 63, in CreateFromDocument
    instance = handler.rootObject()
  File "pyxb/binding/saxer.py", line 285, in rootObject
    raise pyxb.UnrecognizedDOMRootNodeError(self.__rootObject)
pyxb.exceptions_.UnrecognizedDOMRootNodeError: <pyxb.utils.saxdom.Element object at 0x7f30ba4ac550>

# or, perhaps, some kind of unique identifier:
>>> root.item[1].hypothetical_unique_identifier()
'//root/item/1'
>>> sub_node = CreateFromDocument(sample).find_node('//root/item/1')
<binding.Item object at 0x7f30ba4a5d50>

这当然不起作用,因为item根据架构不能成为根节点。有没有办法只解析一个子树,取回一个项目?

或者,是否有某种方法可以唯一标识子节点,以便我以后找到它?

4

2 回答 2

0

PyXB 无法解析以非全局元素开头的文档,因为非全局元素的验证自动机状态不是开始状态。

虽然我最初考虑支持XPath之类的东西,但它从未实现过,也没有一个标准的唯一标识符来承载结构信息。如果您需要标记成员元素,以便您可以将其删除,然后将其放回原来的位置,您可以为对象分配其他属性并在应用程序级别使用它们;例如:

e = root.item[1]
e.__mytag = '//root/item/1'

然后,您可以编写一个遍历对象树以搜索匹配项的函数。当然,这样的属性将只与该实例保持关联,因此随后分配不同的对象root.item[1]不会自动继承相同的属性。

于 2015-10-09T20:18:44.093 回答
0

我最终这样做的方法是使用元素的起始行和列号来识别它。

我将此 mixin 添加到我的所有元素中:

class IdentifierMixin(object):
    """
    Adds an identifier property unique to this node that can be used to locate
    it in the document later.
    """
    @property
    def identifier(self):
        return '%s-%s' % (self._location().lineNumber, self._location().columnNumber)

然后使用此函数稍后查找节点:

def find_by_identifier(root, identifier):
    # BFS over the tree because usually the identifier we're looking for will
    # be close to the root.
    stack = collections.deque([root])
    while stack:
        node = stack.popleft()
        if node.identifier == identifier:
            return node
        stack.extend(node.content())
于 2015-10-09T20:55:01.520 回答