From 069383124c4c448325973daed8912f40b62b3bf1 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Mon, 18 Mar 2013 18:39:18 +0000 Subject: [PATCH] Fixed missing namespace attribute problem Error was: ExpatError: unbound prefix --- merge.py | 6 +++--- tests/local-ns.xml | 17 +++++++++++++++++ tests/testlocal.py | 18 ++++++++++++++++++ xmltools.py | 31 ++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 tests/local-ns.xml diff --git a/merge.py b/merge.py index 002f20e..29c0340 100644 --- a/merge.py +++ b/merge.py @@ -176,7 +176,7 @@ def merge(data, local): else: old_command = group_context.commands.get(name_expr, None) if not (old_command and nodesEqual(old_command, new_command)): - new_commands.append(master_doc.importNode(new_command, True)) + new_commands.append(xmltools.import_node(master_doc, new_command)) # If we have additional requirements or commands, we'll need to create a subgroup and add them if len(new_impl_context.requires) > len(group_context.requires) or new_commands or need_new_group_for_main: @@ -187,7 +187,7 @@ def merge(data, local): for y in group_context.requires: if nodesEqual(x, y): break else: - req = master_doc.importNode(x, True) + req = xmltools.import_node(master_doc, x) #print "Add", req xmltools.insert_element(req, group) for c in new_commands: @@ -199,7 +199,7 @@ def merge(data, local): group_context = Context(group) - new_impl = master_doc.importNode(impl, True) + new_impl = xmltools.import_node(master_doc, impl) # Attributes might have been set on a parent group; move to the impl for name in new_impl_context.attribs: diff --git a/tests/local-ns.xml b/tests/local-ns.xml new file mode 100644 index 0000000..5062959 --- /dev/null +++ b/tests/local-ns.xml @@ -0,0 +1,17 @@ + + + hello + prints hello + + + + + + + + + + + + diff --git a/tests/testlocal.py b/tests/testlocal.py index 08dd23c..c798d35 100755 --- a/tests/testlocal.py +++ b/tests/testlocal.py @@ -29,6 +29,7 @@ local_file = os.path.join(os.path.dirname(__file__), 'local.xml') local_file_req = os.path.join(os.path.dirname(__file__), 'local-req.xml') local_file_if = os.path.join(os.path.dirname(__file__), 'local-if.xml') local_file_command = os.path.join(os.path.dirname(__file__), 'local-command.xml') +local_file_ns = os.path.join(os.path.dirname(__file__), 'local-ns.xml') local_file_main_and_command = os.path.join(os.path.dirname(__file__), 'local-main-and-command.xml') local_file_zi13 = os.path.join(os.path.dirname(__file__), 'zeroinstall-injector-1.3.xml') @@ -138,6 +139,23 @@ class TestLocal(unittest.TestCase): assert len(minidom.parseString(master_xml).documentElement.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 2 + def testMergeNS(self): + master_xml = merge.merge(header + footer, local_file_ns) + master = parse(master_xml) + assert master.url == 'http://test/hello.xml', master + assert len(master.implementations) == 1 + commands = master.implementations['sha1=003'].commands + assert len(commands) == 1 + assert commands['run'].path == 'run.sh', commands['run'].path + + new_root = minidom.parseString(master_xml).documentElement + assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'group')) == 1 + assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'requires')) == 1 + assert len(new_root.getElementsByTagNameNS(XMLNS_IFACE, 'command')) == 1 + + foo_test, = new_root.getElementsByTagNameNS('http://mynamespace/foo', 'test') + foo1_test, = new_root.getElementsByTagNameNS('http://myother/foo', 'test') + def testMergeCommand(self): # We create a new group inside this one, sharing the and adding the master_xml = merge.merge(header + """ diff --git a/xmltools.py b/xmltools.py index ee823a1..d28f9e8 100644 --- a/xmltools.py +++ b/xmltools.py @@ -147,6 +147,8 @@ def register_namespace(namespace, prefix = None): @param prefix: suggested prefix @return: the actual prefix """ + if namespace == XMLNS_INTERFACE: + return None existing_prefix = namespace_prefixes.get(namespace, None) if existing_prefix: return existing_prefix @@ -158,7 +160,7 @@ def register_namespace(namespace, prefix = None): orig_prefix = prefix n = 0 while prefix in namespace_prefixes.values(): - print "Prefix %s already in %s, not %s" % (prefix, namespace_prefixes, namespace) + #print "Prefix %s already in %s, not %s" % (prefix, namespace_prefixes, namespace) n += 1 prefix = orig_prefix + str(n) namespace_prefixes[namespace] = prefix @@ -173,3 +175,30 @@ def add_attribute_ns(element, uri, name, value): prefix = register_namespace(uri) element.setAttributeNS(uri, '%s:%s' % (prefix, name), value) element.ownerDocument.documentElement.setAttributeNS(XMLNS_NAMESPACE, 'xmlns:' + prefix, uri) + +def import_node(target_doc, source_node): + """Import a node for a new document, fixing up namespace prefixes as we go.""" + target_root = target_doc.documentElement + + new_node = target_doc.importNode(source_node, True) + def fixup(elem): + elem.prefix = register_namespace(elem.namespaceURI, elem.prefix) + if elem.prefix: + elem.tagName = elem.nodeName = '%s:%s' % (elem.prefix, elem.localName) + target_root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns:' + elem.prefix, elem.namespaceURI) + + for (uri, name), value in list(elem.attributes.itemsNS()): + if uri == XMLNS_NAMESPACE: + elem.removeAttributeNS(uri, name) + elif uri: + new_prefix = register_namespace(uri) + target_root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns:' + new_prefix, uri) + elem.removeAttributeNS(uri, name) + elem.setAttributeNS(uri, '%s:%s' % (new_prefix, name), value) + + for child in elem.childNodes: + if child.nodeType == Node.ELEMENT_NODE: + fixup(child) + + fixup(new_node) + return new_node -- 2.11.4.GIT