[lxml-dev] namespace strangeness in lxml 1.1
Using python-lxml 1.1.1-1 which comes with Debian Etch, I am noticing some odd behavior in how lxml handles attribute namespaces, and namespaces in general. In the following code, all actual namespace urls should be mapped to namespaces in the resulting output, and they are, except if an attribute is involved: type="{http://domain2.info}someattribute Is this an lxml/libxml2 bug? The second odd behavior is that, for subelements, all the namespace declarations are automatically redeclared in the subelement tag, which is redundant. Does anyone know how to get around these problems? from lxml import etree NS1_NAMESPACE = "http://domain1.info" NS2_NAMESPACE = "http://domain2.info" NS1 = "{%s}" % NS1_NAMESPACE NS2 = "{%s}" % NS2_NAMESPACE NSMAP = {"NS1" : NS1_NAMESPACE , "NS2" : NS2_NAMESPACE} root = etree.Element(NS1 + "firstelement", nsmap=NSMAP) element = etree.Element(NS2 + "secondelement", nsmap=NSMAP, type = NS2 + "someattribute") root.append(element) print etree.tostring(root,pretty_print=True) Which results in the following output: <NS1:firstelement xmlns:NS1="http://domain1.info" xmlns:NS2="http://domain2.info"> <NS2:secondelement xmlns:NS1="http://domain1.info" xmlns:NS2="http://domain2.info" type="{http://domain2.info}someattribute"/> </NS1:firstelement>
On Mon, 2008-06-30 at 20:11 +0000, Eric Jahn wrote:
...The second odd behavior is that, for subelements, all the namespace declarations are automatically redeclared in the subelement tag, which is redundant.
I see that this second error goes away when I use child1 = etree.SubElement(root,NS2 + "secondelement", nsmap=NSMAP, type = NS2 + "someattribute") instead of root = etree.Element(NS1 + "firstelement", nsmap=NSMAP) element = etree.Element(NS2 + "secondelement", nsmap=NSMAP, type = NS2 + "someattribute") root.append(element) -Eric
Hi, Eric Jahn wrote:
type="{http://domain2.info}someattribute
element = etree.Element(NS2 + "secondelement", nsmap=NSMAP, type = NS2 + "someattribute")
You are setting a namespace as attribute /value/ here, not as attribute /name/. lxml will not modify content unless you tell it to do so. If you want it to replace the namespace by a resolved prefix, use type = etree.QName(NS2 + "...") If it's just a mistake and you wanted to set the attribute /namespace/ instead, pass attrib = {NS2 + "someattribute" : "somevalue"} to the Element factory. There should also be a section on this in the tutorial IIRC. Stefan
On Tue, 2008-07-01 at 07:20 +0200, Stefan Behnel wrote:
... You are setting a namespace as attribute /value/ here, not as attribute /name/. ...
Stefan, thank you very much for the response. Yes, I am intending to set the namespace in an attribute value (not attribute name) here as I am creating an XML Schema Document with lxml, not an XML Instance Document. I apologize for not clarifying that in my post.
lxml will not modify content unless you tell it to do so. If you want it to replace the namespace by a resolved prefix, use
type = etree.QName(NS2 + "...")
No, I don't want the prefix resolved the the url, so I guess my only option is to do something like the following and just pass the type value a string with the namespace prefix explicity stated: child1 = etree.SubElement(root,NS2 + "secondelement", nsmap=NSMAP, type = "NS2:someattribute") I think the tutorial could benefit from a small section on creating schema docs as opposed to instance docs. I'd be happy to submit the start of such a new section? Would this be helpful? I know it would have saved me a little time... Thanks again for your help! -Eric
Hi, Eric Jahn wrote:
On Tue, 2008-07-01 at 07:20 +0200, Stefan Behnel wrote:
type = etree.QName(NS2 + "...")
No, I don't want the prefix resolved the the url, so I guess my only option is to do something like the following and just pass the type value a string with the namespace prefix explicity stated:
child1 = etree.SubElement(root,NS2 + "secondelement", nsmap=NSMAP, type = "NS2:someattribute")
Ah, now that you mention it, the above doesn't actually work. It only works for element text, not for attributes. I'll see if I can change that.
I think the tutorial could benefit from a small section on creating schema docs as opposed to instance docs. I'd be happy to submit the start of such a new section? Would this be helpful? I know it would have saved me a little time...
Please do, any contribution is appreciated. Stefan
Hi, coming back to this after a while... Eric Jahn wrote:
On Tue, 2008-07-01 at 07:20 +0200, Stefan Behnel wrote:
If you want it to replace the namespace by a resolved prefix, use
type = etree.QName(NS2 + "...")
No, I don't want the prefix resolved the the url, so I guess my only option is to do something like the following and just pass the type value a string with the namespace prefix explicity stated:
child1 = etree.SubElement(root,NS2 + "secondelement", nsmap=NSMAP, type = "NS2:someattribute")
I think you misunderstood my example (and apparently didn't try it on your side). Isn't this what you wanted: >>> import lxml.etree as et >>> root = et.XML('<root xmlns:a="http://my/ns"><el/></root>') >>> root[0].set("type", et.QName("{http://my/ns}tname")) >>> et.tostring(root) '<root xmlns:a="http://my/ns"><el type="a:tname"/></root>' This has been working for quite a while now. Stefan
On Wed, 2008-08-20 at 09:07 +0200, Stefan Behnel wrote:
>>> import lxml.etree as et >>> root = et.XML('<root xmlns:a="http://my/ns"><el/></root>') >>> root[0].set("type", et.QName("{http://my/ns}tname")) >>> et.tostring(root) '<root xmlns:a="http://my/ns"><el type="a:tname"/></root>'
Stefan, this worked, thank you! -Eric
participants (2)
-
Eric Jahn
-
Stefan Behnel