diff options
| author | Stefan Behnel <stefan_ml@behnel.de> | 2016-08-20 13:40:42 +0200 |
|---|---|---|
| committer | Stefan Behnel <stefan_ml@behnel.de> | 2016-08-20 13:40:42 +0200 |
| commit | 8c19b669360bb66726571e80884f7f5ca5e30b9a (patch) | |
| tree | cc0223fd1a28c17ff81dc15e3f36f4f1e5bfa601 /src | |
| parent | c3724df167a22ffb13cb871c10a6954ca71fc2cf (diff) | |
| download | python-lxml-8c19b669360bb66726571e80884f7f5ca5e30b9a.tar.gz | |
Revert "Revert "Merge pull request #184 from Pelleplutt/master""
This reverts commit 6ea2dab5d5d5b35225a3342faeb705f6197766a5.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lxml/proxy.pxi | 47 | ||||
| -rw-r--r-- | src/lxml/serializer.pxi | 5 | ||||
| -rw-r--r-- | src/lxml/tests/test_etree.py | 4 |
3 files changed, 44 insertions, 12 deletions
diff --git a/src/lxml/proxy.pxi b/src/lxml/proxy.pxi index 959b5be3..01bb8f49 100644 --- a/src/lxml/proxy.pxi +++ b/src/lxml/proxy.pxi @@ -49,10 +49,11 @@ cdef inline int _unregisterProxy(_Element proxy) except -1: # temporarily make a node the root node of its document cdef xmlDoc* _fakeRootDoc(xmlDoc* c_base_doc, xmlNode* c_node) except NULL: - return _plainFakeRootDoc(c_base_doc, c_node, 1) + return _plainFakeRootDoc(c_base_doc=c_base_doc, c_node=c_node, + with_siblings=1, used_only=0) cdef xmlDoc* _plainFakeRootDoc(xmlDoc* c_base_doc, xmlNode* c_node, - bint with_siblings) except NULL: + bint with_siblings, bint used_only=1) except NULL: # build a temporary document that has the given node as root node # note that copy and original must not be modified during its lifetime!! # always call _destroyFakeDoc() after use! @@ -69,7 +70,7 @@ cdef xmlDoc* _plainFakeRootDoc(xmlDoc* c_base_doc, xmlNode* c_node, c_doc = _copyDoc(c_base_doc, 0) # non recursive! c_new_root = tree.xmlDocCopyNode(c_node, c_doc, 2) # non recursive! tree.xmlDocSetRootElement(c_doc, c_new_root) - _copyParentNamespaces(c_node, c_new_root) + _copyParentNamespaces(c_node, c_new_root, used_only) c_new_root.children = c_node.children c_new_root.last = c_node.last @@ -191,20 +192,50 @@ cdef int canDeallocateChildNodes(xmlNode* c_parent): ################################################################################ # fix _Document references and namespaces when a node changes documents -cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node) nogil: - u"""Copy the namespaces of all ancestors of c_from_node to c_to_node. +cdef void _copyParentNamespaces(xmlNode* c_from_node, xmlNode* c_to_node, bint used_only=1) nogil: + u"""Copy the namespaces of all ancestors of c_from_node to c_to_node that are used by c_to_node. """ cdef xmlNode* c_parent + cdef xmlNode* c_node cdef xmlNs* c_ns cdef xmlNs* c_new_ns - cdef int prefix_known c_parent = c_from_node.parent + cdef _nscache c_ns_cache = [NULL, 0, 0] + cdef _ns_update_map c_ns_entry + cdef bint should_copy = 0 + + if used_only: + # Build up a cache for each of the ns prefixes used in the elements we will + # copy over, then use prescence in the cache as a basis for allowing the + # copy of the namespace. + c_node = c_from_node.children + tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_from_node, c_node, 1) + if c_node.ns is not NULL: + c_ns = NULL + for c_ns_entry in c_ns_cache.ns_map[:c_ns_cache.last]: + if c_node.ns is c_ns_entry.old: + c_ns = c_ns_entry.old + break + + if c_ns is NULL: + with gil: + _appendToNsCache(&c_ns_cache, c_node.ns, NULL) + tree.END_FOR_EACH_ELEMENT_FROM(c_node) + while c_parent and (tree._isElementOrXInclude(c_parent) or c_parent.type == tree.XML_DOCUMENT_NODE): c_new_ns = c_parent.nsDef while c_new_ns: - # libxml2 will check if the prefix is already defined - tree.xmlNewNs(c_to_node, c_new_ns.href, c_new_ns.prefix) + if used_only: + should_copy = 0 + for c_ns_entry in c_ns_cache.ns_map[:c_ns_cache.last]: + if c_new_ns is c_ns_entry.old: + should_copy = 1 + break + + if not used_only or should_copy: + # libxml2 will check if the prefix is already defined + tree.xmlNewNs(c_to_node, c_new_ns.href, c_new_ns.prefix) c_new_ns = c_new_ns.next c_parent = c_parent.parent diff --git a/src/lxml/serializer.pxi b/src/lxml/serializer.pxi index f346bb11..b901d889 100644 --- a/src/lxml/serializer.pxi +++ b/src/lxml/serializer.pxi @@ -159,7 +159,8 @@ cdef bytes _tostringC14N(element_or_tree, bint exclusive, bint with_comments, in if isinstance(element_or_tree, _Element): _assertValidNode(<_Element>element_or_tree) doc = (<_Element>element_or_tree)._doc - c_doc = _plainFakeRootDoc(doc._c_doc, (<_Element>element_or_tree)._c_node, 0) + c_doc = _plainFakeRootDoc(c_base_doc=doc._c_doc, c_node=(<_Element>element_or_tree)._c_node, + with_siblings=0, used_only=1) else: doc = _documentOrRaise(element_or_tree) _assertValidDoc(doc) @@ -234,7 +235,7 @@ cdef void _writeNodeToBuffer(tree.xmlOutputBuffer* c_buffer, if not c_nsdecl_node: c_buffer.error = xmlerror.XML_ERR_NO_MEMORY return - _copyParentNamespaces(c_node, c_nsdecl_node) + _copyParentNamespaces(c_from_node=c_node, c_to_node=c_nsdecl_node, used_only=0) c_nsdecl_node.parent = c_node.parent c_nsdecl_node.children = c_node.children diff --git a/src/lxml/tests/test_etree.py b/src/lxml/tests/test_etree.py index 4ec59096..bcf97971 100644 --- a/src/lxml/tests/test_etree.py +++ b/src/lxml/tests/test_etree.py @@ -4196,14 +4196,14 @@ class ETreeC14NTestCase(HelperTestCase): s) s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=False) - self.assertEqual(_bytes('<z:b xmlns="http://abc" xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'), + self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'), s) s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True) self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'), s) s = etree.tostring(tree.getroot()[0], method='c14n', exclusive=True, inclusive_ns_prefixes=['y']) - self.assertEqual(_bytes('<z:b xmlns:y="http://bcd" xmlns:z="http://cde"></z:b>'), + self.assertEqual(_bytes('<z:b xmlns:z="http://cde"></z:b>'), s) def test_c14n_tostring_inclusive_ns_prefixes(self): |
