Exclusive canonicalization ignores inclusive_ns_prefixes

Bug #1704826 reported by Bacon Ranch
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
lxml
New
Undecided
Unassigned

Bug Description

I'm trying to use the write_c14n method on ElementTree with exclusive=True and a list of prefixes provided to the inclusive_ns_prefixes argument. From my understanding, this should produce the exclusive canonicaliztion of the document except for prefixes listed in inclusive_ns_prefixes, which should be handled inclusively (ie: for prefixes listed in inclusive_ns_prefixes, treat them as if the exclusive argument was set to False).

Unfortunately, it seems that the inclusive_ns_prefixes list is being ignored. Let met explain with an example.

I have taken my example from Section 2.2 of the Exclusive XML Canonicalization specification: https://www.w3.org/TR/xml-exc-c14n/

First, let's start with an inclusive canonicalization:
Here's the source XML:
   <n0:local xmlns:n0="http://example.com/n0"
             xmlns:n3="http://example.com/n3">
      <n1:elem2 xmlns:n1="http://example.com/n1">
          <n3:stuff xmlns:n3="http://example.com/n3"/>
      </n1:elem2>
   </n0:local>

And here's its representation with ElementMaker objects, as well as the code to produce the canonicalization:

from lxml.builder import ElementMaker
from lxml.etree import ElementTree, Element
from lxml import etree
from StringIO import StringIO

def stringify(elem):
    f = StringIO()
    et = ElementTree(elem)
    et.write_c14n(f, exclusive=False)
    f.seek(0)
    return f.read()

n0 = ElementMaker(namespace='http://example.com/n0', nsmap={'n0':'http://example.com/n0', 'n3':'http://example.com/n3'})
n1 = ElementMaker(namespace='http://example.com/n1', nsmap={'n1':'http://example.com/n1'})
n3 = ElementMaker(namespace='http://example.com/n3', nsmap={'n3':'http://example.com/n3'})

elem = n0.local(n1.elem2(n3.stuff()))

print stringify(elem.getchildren()[0])

The output of the print statement produces:
<n1:elem2 xmlns:n0="http://example.com/n0" xmlns:n1="http://example.com/n1" xmlns:n3="http://example.com/n3"><n3:stuff></n3:stuff></n1:elem2>

Now, in the et.write_c14n call, let's say I change to exclusive=True:
<n1:elem2 xmlns:n1="http://example.com/n1"><n3:stuff xmlns:n3="http://example.com/n3"></n3:stuff></n1:elem2>

Both of these examples match the output in the W3 webpage I referenced above. In the first output, the parent n0 element provides context that is included in the child. This seems like the correct behavior for an inclusive canonicalization. In the second output, we're in exclusive mode, and namespaces are only included when needed and only if they haven't already been included by an ancestor. All's great so far, so what's wrong?

Well, let's now modify the et.write_c14n call to use have exclusive=True and also provide inclusive_ns_prefixes=['n3']:
<n1:elem2 xmlns:n1="http://example.com/n1"><n3:stuff xmlns:n3="http://example.com/n3"></n3:stuff></n1:elem2>

Eh? It's exactly the same as in the second output! That's not right. According to our inclusive_ns_prefixes argument, the n3 namespace should be handled inclusively. The correct output should be (I think- I've manually adjusted this):
<n1:elem2 xmlns:n1="http://example.com/n1" xmlns:n3="http://example.com/n3"><n3:stuff></n3:stuff></n1:elem2>

Notice how the n3 namespace was pushed to the top-level element in my correction. It's odd that lxml didn't produce that on it's own, considering lxml's documentation for the write_c14n method: "The inclusive_ns_prefixes should be a list of namespace strings (i.e. ['xs', 'xsi']) that will be promoted to the top-level element during exclusive C14N serialisation."

Python : sys.version_info(major=2, minor=7, micro=13, releaselevel='final', serial=0)
lxml.etree : (3, 8, 0, 0)
libxml used : (2, 9, 4)
libxml compiled : (2, 9, 4)
libxslt used : (1, 1, 29)
libxslt compiled : (1, 1, 29)

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.