|
|
@@ -1,43 +1,42 @@ |
|
|
|
#! /usr/bin/env python |
|
|
|
"""Compatibility module, imported by ZSI if you don't have PyXML 0.7. |
|
|
|
|
|
|
|
No copyright violations -- we're only using parts of PyXML that we |
|
|
|
wrote. |
|
|
|
""" |
|
|
|
|
|
|
|
_copyright = '''ZSI: Zolera Soap Infrastructure. |
|
|
|
|
|
|
|
Copyright 2001, Zolera Systems, Inc. All Rights Reserved. |
|
|
|
Copyright 2002-2003, Rich Salz. All Rights Reserved. |
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
|
|
copy of this software and associated documentation files (the "Software"), |
|
|
|
to deal in the Software without restriction, including without limitation |
|
|
|
the rights to use, copy, modify, merge, publish, distribute, and/or |
|
|
|
sell copies of the Software, and to permit persons to whom the Software |
|
|
|
is furnished to do so, provided that the above copyright notice(s) and |
|
|
|
this permission notice appear in all copies of the Software and that |
|
|
|
both the above copyright notice(s) and this permission notice appear in |
|
|
|
supporting documentation. |
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT |
|
|
|
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS |
|
|
|
INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT |
|
|
|
OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
|
|
|
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
|
|
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE |
|
|
|
OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
|
|
|
|
Except as contained in this notice, the name of a copyright holder |
|
|
|
shall not be used in advertising or otherwise to promote the sale, use |
|
|
|
or other dealings in this Software without prior written authorization |
|
|
|
of the copyright holder. |
|
|
|
'''XML Canonicalization |
|
|
|
|
|
|
|
Patches Applied to xml.dom.ext.c14n: |
|
|
|
http://sourceforge.net/projects/pyxml/ |
|
|
|
|
|
|
|
[ 1444526 ] c14n.py: http://www.w3.org/TR/xml-exc-c14n/ fix |
|
|
|
-- includes [ 829905 ] c14n.py fix for bug #825115, |
|
|
|
Date Submitted: 2003-10-24 23:43 |
|
|
|
-- include dependent namespace declarations declared in ancestor nodes |
|
|
|
(checking attributes and tags), |
|
|
|
-- handle InclusiveNamespaces PrefixList parameter |
|
|
|
|
|
|
|
This module generates canonical XML of a document or element. |
|
|
|
http://www.w3.org/TR/2001/REC-xml-c14n-20010315 |
|
|
|
and includes a prototype of exclusive canonicalization |
|
|
|
http://www.w3.org/Signature/Drafts/xml-exc-c14n |
|
|
|
|
|
|
|
Requires PyXML 0.7.0 or later. |
|
|
|
|
|
|
|
Known issues if using Ft.Lib.pDomlette: |
|
|
|
1. Unicode |
|
|
|
2. does not white space normalize attributes of type NMTOKEN and ID? |
|
|
|
3. seems to be include "\n" after importing external entities? |
|
|
|
|
|
|
|
Note, this version processes a DOM tree, and consequently it processes |
|
|
|
namespace nodes as attributes, not from a node's namespace axis. This |
|
|
|
permits simple document and element canonicalization without |
|
|
|
XPath. When XPath is used, the XPath result node list is passed and used to |
|
|
|
determine if the node is in the XPath result list, but little else. |
|
|
|
|
|
|
|
Authors: |
|
|
|
"Joseph M. Reagle Jr." <reagle@w3.org> |
|
|
|
"Rich Salz" <rsalz@zolera.com> |
|
|
|
|
|
|
|
$Date$ by $Author$ |
|
|
|
''' |
|
|
|
|
|
|
|
_copyright += "\n\nPortions are also: " |
|
|
|
_copyright += '''Copyright 2001, Zolera Systems Inc. All Rights Reserved. |
|
|
|
_copyright = '''Copyright 2001, Zolera Systems Inc. All Rights Reserved. |
|
|
|
Copyright 2001, MIT. All Rights Reserved. |
|
|
|
|
|
|
|
Distributed under the terms of: |
|
|
@@ -48,184 +47,25 @@ or |
|
|
|
http://www.w3.org/Consortium/Legal/copyright-software-19980720 |
|
|
|
''' |
|
|
|
|
|
|
|
import string |
|
|
|
from xml.dom import Node |
|
|
|
from Namespaces import XMLNS |
|
|
|
import cStringIO as StringIO |
|
|
|
try: |
|
|
|
from xml.dom.ext import c14n |
|
|
|
except ImportError, ex: |
|
|
|
_implementation2 = None |
|
|
|
_attrs = lambda E: (E.attributes and E.attributes.values()) or [] |
|
|
|
_children = lambda E: E.childNodes or [] |
|
|
|
else: |
|
|
|
class _implementation2(c14n._implementation): |
|
|
|
"""Patch for exclusive c14n |
|
|
|
""" |
|
|
|
def __init__(self, node, write, **kw): |
|
|
|
self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') |
|
|
|
self._exclusive = None |
|
|
|
if node.nodeType == Node.ELEMENT_NODE: |
|
|
|
if not c14n._inclusive(self): |
|
|
|
self._exclusive = self._inherit_context(node) |
|
|
|
c14n._implementation.__init__(self, node, write, **kw) |
|
|
|
|
|
|
|
def _do_element(self, node, initial_other_attrs = []): |
|
|
|
"""Patch for the xml.dom.ext.c14n implemenation _do_element method. |
|
|
|
This fixes a problem with sorting of namespaces. |
|
|
|
""" |
|
|
|
# Get state (from the stack) make local copies. |
|
|
|
# ns_parent -- NS declarations in parent |
|
|
|
# ns_rendered -- NS nodes rendered by ancestors |
|
|
|
# ns_local -- NS declarations relevant to this element |
|
|
|
# xml_attrs -- Attributes in XML namespace from parent |
|
|
|
# xml_attrs_local -- Local attributes in XML namespace. |
|
|
|
ns_parent, ns_rendered, xml_attrs = \ |
|
|
|
self.state[0], self.state[1].copy(), self.state[2].copy() #0422 |
|
|
|
ns_local = ns_parent.copy() |
|
|
|
xml_attrs_local = {} |
|
|
|
|
|
|
|
# Divide attributes into NS, XML, and others. |
|
|
|
#other_attrs = initial_other_attrs[:] |
|
|
|
other_attrs = [] |
|
|
|
sort_these_attrs = initial_other_attrs[:] |
|
|
|
|
|
|
|
in_subset = c14n._in_subset(self.subset, node) |
|
|
|
#for a in _attrs(node): |
|
|
|
sort_these_attrs +=c14n._attrs(node) |
|
|
|
|
|
|
|
for a in sort_these_attrs: |
|
|
|
if a.namespaceURI == c14n.XMLNS.BASE: |
|
|
|
n = a.nodeName |
|
|
|
if n == "xmlns:": n = "xmlns" # DOM bug workaround |
|
|
|
ns_local[n] = a.nodeValue |
|
|
|
elif a.namespaceURI == c14n.XMLNS.XML: |
|
|
|
if c14n._inclusive(self) or (in_subset and c14n._in_subset(self.subset, a)): #020925 Test to see if attribute node in subset |
|
|
|
xml_attrs_local[a.nodeName] = a #0426 |
|
|
|
else: |
|
|
|
if c14n._in_subset(self.subset, a): #020925 Test to see if attribute node in subset |
|
|
|
other_attrs.append(a) |
|
|
|
#add local xml:foo attributes to ancestor's xml:foo attributes |
|
|
|
xml_attrs.update(xml_attrs_local) |
|
|
|
|
|
|
|
# Render the node |
|
|
|
W, name = self.write, None |
|
|
|
if in_subset: |
|
|
|
name = node.nodeName |
|
|
|
W('<') |
|
|
|
W(name) |
|
|
|
|
|
|
|
# Create list of NS attributes to render. |
|
|
|
ns_to_render = [] |
|
|
|
for n,v in ns_local.items(): |
|
|
|
|
|
|
|
# If default namespace is XMLNS.BASE or empty, |
|
|
|
# and if an ancestor was the same |
|
|
|
if n == "xmlns" and v in [ c14n.XMLNS.BASE, '' ] \ |
|
|
|
and ns_rendered.get('xmlns') in [ c14n.XMLNS.BASE, '', None ]: |
|
|
|
continue |
|
|
|
|
|
|
|
# "omit namespace node with local name xml, which defines |
|
|
|
# the xml prefix, if its string value is |
|
|
|
# http://www.w3.org/XML/1998/namespace." |
|
|
|
if n in ["xmlns:xml", "xml"] \ |
|
|
|
and v in [ 'http://www.w3.org/XML/1998/namespace' ]: |
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
# If not previously rendered |
|
|
|
# and it's inclusive or utilized |
|
|
|
if (n,v) not in ns_rendered.items() \ |
|
|
|
and (c14n._inclusive(self) or \ |
|
|
|
c14n._utilized(n, node, other_attrs, self.unsuppressedPrefixes)): |
|
|
|
ns_to_render.append((n, v)) |
|
|
|
|
|
|
|
##################################### |
|
|
|
# JRB |
|
|
|
##################################### |
|
|
|
if not c14n._inclusive(self): |
|
|
|
if node.prefix is None: |
|
|
|
look_for = [('xmlns', node.namespaceURI),] |
|
|
|
else: |
|
|
|
look_for = [('xmlns:%s' %node.prefix, node.namespaceURI),] |
|
|
|
for a in c14n._attrs(node): |
|
|
|
if a.namespaceURI != XMLNS.BASE: |
|
|
|
#print "ATTRIBUTE: ", (a.namespaceURI, a.prefix) |
|
|
|
if a.prefix: |
|
|
|
#print "APREFIX: ", a.prefix |
|
|
|
look_for.append(('xmlns:%s' %a.prefix, a.namespaceURI)) |
|
|
|
|
|
|
|
for key,namespaceURI in look_for: |
|
|
|
if ns_rendered.has_key(key): |
|
|
|
if ns_rendered[key] == namespaceURI: |
|
|
|
# Dont write out |
|
|
|
pass |
|
|
|
else: |
|
|
|
#ns_to_render += [(key, namespaceURI)] |
|
|
|
pass |
|
|
|
elif (key,namespaceURI) in ns_to_render: |
|
|
|
# Dont write out |
|
|
|
pass |
|
|
|
else: |
|
|
|
# Unique write out, rewrite to render |
|
|
|
ns_local[key] = namespaceURI |
|
|
|
for a in self._exclusive: |
|
|
|
if a.nodeName == key: |
|
|
|
#self._do_attr(a.nodeName, a.value) |
|
|
|
#ns_rendered[key] = namespaceURI |
|
|
|
#break |
|
|
|
ns_to_render += [(a.nodeName, a.value)] |
|
|
|
break |
|
|
|
elif key is None and a.nodeName == 'xmlns': |
|
|
|
#print "DEFAULT: ", (a.nodeName, a.value) |
|
|
|
ns_to_render += [(a.nodeName, a.value)] |
|
|
|
break |
|
|
|
#print "KEY: ", key |
|
|
|
else: |
|
|
|
#print "Look for: ", look_for |
|
|
|
#print "NS_TO_RENDER: ", ns_to_render |
|
|
|
#print "EXCLUSIVE NS: ", map(lambda f: (f.nodeName,f.value),self._exclusive) |
|
|
|
raise RuntimeError, \ |
|
|
|
'can not find namespace (%s="%s") for exclusive canonicalization'\ |
|
|
|
%(key, namespaceURI) |
|
|
|
##################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Sort and render the ns, marking what was rendered. |
|
|
|
ns_to_render.sort(c14n._sorter_ns) |
|
|
|
for n,v in ns_to_render: |
|
|
|
#XXX JRB, getting 'xmlns,None' here when xmlns='' |
|
|
|
if v: self._do_attr(n, v) |
|
|
|
else: |
|
|
|
v = '' |
|
|
|
self._do_attr(n, v) |
|
|
|
ns_rendered[n]=v #0417 |
|
|
|
|
|
|
|
# If exclusive or the parent is in the subset, add the local xml attributes |
|
|
|
# Else, add all local and ancestor xml attributes |
|
|
|
# Sort and render the attributes. |
|
|
|
if not c14n._inclusive(self) or c14n._in_subset(self.subset,node.parentNode): #0426 |
|
|
|
other_attrs.extend(xml_attrs_local.values()) |
|
|
|
else: |
|
|
|
other_attrs.extend(xml_attrs.values()) |
|
|
|
#print "OTHER: ", other_attrs |
|
|
|
other_attrs.sort(c14n._sorter) |
|
|
|
for a in other_attrs: |
|
|
|
self._do_attr(a.nodeName, a.value) |
|
|
|
W('>') |
|
|
|
|
|
|
|
|
|
|
|
# Push state, recurse, pop state. |
|
|
|
state, self.state = self.state, (ns_local, ns_rendered, xml_attrs) |
|
|
|
for c in c14n._children(node): |
|
|
|
c14n._implementation.handlers[c.nodeType](self, c) |
|
|
|
self.state = state |
|
|
|
|
|
|
|
if name: W('</%s>' % name) |
|
|
|
c14n._implementation.handlers[c14n.Node.ELEMENT_NODE] = _do_element |
|
|
|
|
|
|
|
|
|
|
|
_IN_XML_NS = lambda n: n.namespaceURI == XMLNS.XML |
|
|
|
try: |
|
|
|
from xml.ns import XMLNS |
|
|
|
except: |
|
|
|
class XMLNS: |
|
|
|
BASE = "http://www.w3.org/2000/xmlns/" |
|
|
|
XML = "http://www.w3.org/XML/1998/namespace" |
|
|
|
try: |
|
|
|
import cStringIO |
|
|
|
StringIO = cStringIO |
|
|
|
except ImportError: |
|
|
|
import StringIO |
|
|
|
|
|
|
|
_attrs = lambda E: (E.attributes and E.attributes.values()) or [] |
|
|
|
_children = lambda E: E.childNodes or [] |
|
|
|
_IN_XML_NS = lambda n: n.name.startswith("xmlns") |
|
|
|
_inclusive = lambda n: n.unsuppressedPrefixes == None |
|
|
|
|
|
|
|
|
|
|
|
# Does a document/PI has lesser/greater document order than the |
|
|
|
# first element? |
|
|
@@ -251,24 +91,53 @@ def _sorter_ns(n1,n2): |
|
|
|
def _utilized(n, node, other_attrs, unsuppressedPrefixes): |
|
|
|
'''_utilized(n, node, other_attrs, unsuppressedPrefixes) -> boolean |
|
|
|
Return true if that nodespace is utilized within the node''' |
|
|
|
|
|
|
|
if n.startswith('xmlns:'): |
|
|
|
n = n[6:] |
|
|
|
elif n.startswith('xmlns'): |
|
|
|
n = n[5:] |
|
|
|
if n == node.prefix or n in unsuppressedPrefixes: return 1 |
|
|
|
if (n=="" and node.prefix in ["#default", None]) or \ |
|
|
|
n == node.prefix or n in unsuppressedPrefixes: |
|
|
|
return 1 |
|
|
|
for attr in other_attrs: |
|
|
|
if n == attr.prefix: return 1 |
|
|
|
# For exclusive need to look at attributes |
|
|
|
if unsuppressedPrefixes is not None: |
|
|
|
for attr in _attrs(node): |
|
|
|
if n == attr.prefix: return 1 |
|
|
|
return 0 |
|
|
|
|
|
|
|
_in_subset = lambda subset, node: not subset or node in subset |
|
|
|
|
|
|
|
# |
|
|
|
# JRB. Currently there is a bug in do_element, but since the underlying |
|
|
|
# Data Structures in c14n have changed I can't just apply the |
|
|
|
# _implementation2 patch above. But this will work OK for most uses, |
|
|
|
# just not XML Signatures. |
|
|
|
# |
|
|
|
def _inclusiveNamespacePrefixes(node, context, unsuppressedPrefixes): |
|
|
|
'''http://www.w3.org/TR/xml-exc-c14n/ |
|
|
|
InclusiveNamespaces PrefixList parameter, which lists namespace prefixes that |
|
|
|
are handled in the manner described by the Canonical XML Recommendation''' |
|
|
|
inclusive = [] |
|
|
|
if node.prefix: |
|
|
|
usedPrefixes = ['xmlns:%s' %node.prefix] |
|
|
|
else: |
|
|
|
usedPrefixes = ['xmlns'] |
|
|
|
|
|
|
|
for a in _attrs(node): |
|
|
|
if a.nodeName.startswith('xmlns') or not a.prefix: continue |
|
|
|
usedPrefixes.append('xmlns:%s' %a.prefix) |
|
|
|
|
|
|
|
for attr in context: |
|
|
|
n = attr.nodeName |
|
|
|
if n in unsuppressedPrefixes: |
|
|
|
inclusive.append(attr) |
|
|
|
elif n.startswith('xmlns:') and n[6:] in unsuppressedPrefixes: |
|
|
|
inclusive.append(attr) |
|
|
|
elif n.startswith('xmlns') and n[5:] in unsuppressedPrefixes: |
|
|
|
inclusive.append(attr) |
|
|
|
elif attr.nodeName in usedPrefixes: |
|
|
|
inclusive.append(attr) |
|
|
|
|
|
|
|
return inclusive |
|
|
|
|
|
|
|
#_in_subset = lambda subset, node: not subset or node in subset |
|
|
|
_in_subset = lambda subset, node: subset is None or node in subset # rich's tweak |
|
|
|
|
|
|
|
|
|
|
|
class _implementation: |
|
|
|
'''Implementation class for C14N. This accompanies a node during it's |
|
|
|
processing and includes the parameters and processing state.''' |
|
|
@@ -278,25 +147,23 @@ class _implementation: |
|
|
|
|
|
|
|
def __init__(self, node, write, **kw): |
|
|
|
'''Create and run the implementation.''' |
|
|
|
|
|
|
|
self.write = write |
|
|
|
self.subset = kw.get('subset') |
|
|
|
if self.subset: |
|
|
|
self.comments = kw.get('comments', 1) |
|
|
|
else: |
|
|
|
self.comments = kw.get('comments', 0) |
|
|
|
self.comments = kw.get('comments', 0) |
|
|
|
self.unsuppressedPrefixes = kw.get('unsuppressedPrefixes') |
|
|
|
nsdict = kw.get('nsdict', { 'xml': XMLNS.XML, 'xmlns': XMLNS.BASE }) |
|
|
|
|
|
|
|
|
|
|
|
# Processing state. |
|
|
|
self.state = (nsdict, ['xml'], []) |
|
|
|
|
|
|
|
self.state = (nsdict, {'xml':''}, {}) #0422 |
|
|
|
|
|
|
|
if node.nodeType == Node.DOCUMENT_NODE: |
|
|
|
self._do_document(node) |
|
|
|
elif node.nodeType == Node.ELEMENT_NODE: |
|
|
|
self.documentOrder = _Element # At document element |
|
|
|
if self.unsuppressedPrefixes is not None: |
|
|
|
self._do_element(node) |
|
|
|
if not _inclusive(self): |
|
|
|
inherited = _inclusiveNamespacePrefixes(node, self._inherit_context(node), |
|
|
|
self.unsuppressedPrefixes) |
|
|
|
self._do_element(node, inherited) |
|
|
|
else: |
|
|
|
inherited = self._inherit_context(node) |
|
|
|
self._do_element(node, inherited) |
|
|
@@ -355,11 +222,10 @@ class _implementation: |
|
|
|
Process a text or CDATA node. Render various special characters |
|
|
|
as their C14N entity representations.''' |
|
|
|
if not _in_subset(self.subset, node): return |
|
|
|
s = node.data \ |
|
|
|
.replace("&", "&") \ |
|
|
|
.replace("<", "<") \ |
|
|
|
.replace(">", ">") \ |
|
|
|
.replace("\015", "
") |
|
|
|
s = string.replace(node.data, "&", "&") |
|
|
|
s = string.replace(s, "<", "<") |
|
|
|
s = string.replace(s, ">", ">") |
|
|
|
s = string.replace(s, "\015", "
") |
|
|
|
if s: self.write(s) |
|
|
|
handlers[Node.TEXT_NODE] = _do_text |
|
|
|
handlers[Node.CDATA_SECTION_NODE] = _do_text |
|
|
@@ -410,46 +276,51 @@ class _implementation: |
|
|
|
W(' ') |
|
|
|
W(n) |
|
|
|
W('="') |
|
|
|
s = value \ |
|
|
|
.replace("&", "&") \ |
|
|
|
.replace("<", "<") \ |
|
|
|
.replace('"', '"') \ |
|
|
|
.replace('\011', '	') \ |
|
|
|
.replace('\012', '
') \ |
|
|
|
.replace('\015', '
') |
|
|
|
s = string.replace(value, "&", "&") |
|
|
|
s = string.replace(s, "<", "<") |
|
|
|
s = string.replace(s, '"', '"') |
|
|
|
s = string.replace(s, '\011', '	') |
|
|
|
s = string.replace(s, '\012', '
') |
|
|
|
s = string.replace(s, '\015', '
') |
|
|
|
W(s) |
|
|
|
W('"') |
|
|
|
|
|
|
|
|
|
|
|
def _do_element(self, node, initial_other_attrs = []): |
|
|
|
'''_do_element(self, node, initial_other_attrs = []) -> None |
|
|
|
Process an element (and its children).''' |
|
|
|
|
|
|
|
# Get state (from the stack) make local copies. |
|
|
|
# ns_parent -- NS declarations in parent |
|
|
|
# ns_rendered -- NS nodes rendered by ancestors |
|
|
|
# xml_attrs -- Attributes in XML namespace from parent |
|
|
|
# ns_local -- NS declarations relevant to this element |
|
|
|
# ns_parent -- NS declarations in parent |
|
|
|
# ns_rendered -- NS nodes rendered by ancestors |
|
|
|
# ns_local -- NS declarations relevant to this element |
|
|
|
# xml_attrs -- Attributes in XML namespace from parent |
|
|
|
# xml_attrs_local -- Local attributes in XML namespace. |
|
|
|
ns_parent, ns_rendered, xml_attrs = \ |
|
|
|
self.state[0], self.state[1][:], self.state[2][:] |
|
|
|
self.state[0], self.state[1].copy(), self.state[2].copy() #0422 |
|
|
|
ns_local = ns_parent.copy() |
|
|
|
xml_attrs_local = {} |
|
|
|
|
|
|
|
# Divide attributes into NS, XML, and others. |
|
|
|
other_attrs = initial_other_attrs[:] |
|
|
|
other_attrs = [] |
|
|
|
in_subset = _in_subset(self.subset, node) |
|
|
|
for a in _attrs(node): |
|
|
|
for a in _attrs(node) + initial_other_attrs: |
|
|
|
if a.namespaceURI == XMLNS.BASE: |
|
|
|
n = a.nodeName |
|
|
|
if n == "xmlns:": n = "xmlns" # DOM bug workaround |
|
|
|
ns_local[n] = a.nodeValue |
|
|
|
elif a.namespaceURI == XMLNS.XML: |
|
|
|
if self.unsuppressedPrefixes is None or in_subset: |
|
|
|
xml_attrs.append(a) |
|
|
|
if _inclusive(self) or (in_subset and _in_subset(self.subset, a)): #020925 Test to see if attribute node in subset |
|
|
|
xml_attrs_local[a.nodeName] = a #0426 |
|
|
|
else: |
|
|
|
other_attrs.append(a) |
|
|
|
if _in_subset(self.subset, a): #020925 Test to see if attribute node in subset |
|
|
|
other_attrs.append(a) |
|
|
|
#add local xml:foo attributes to ancestor's xml:foo attributes |
|
|
|
xml_attrs.update(xml_attrs_local) |
|
|
|
|
|
|
|
# Render the node |
|
|
|
W, name = self.write, None |
|
|
|
if in_subset: |
|
|
|
if in_subset: |
|
|
|
name = node.nodeName |
|
|
|
W('<') |
|
|
|
W(name) |
|
|
@@ -457,25 +328,25 @@ class _implementation: |
|
|
|
# Create list of NS attributes to render. |
|
|
|
ns_to_render = [] |
|
|
|
for n,v in ns_local.items(): |
|
|
|
pval = ns_parent.get(n) |
|
|
|
|
|
|
|
# If default namespace is XMLNS.BASE or empty, skip |
|
|
|
if n == "xmlns" \ |
|
|
|
and v in [ XMLNS.BASE, '' ] and pval in [ XMLNS.BASE, '' ]: |
|
|
|
# If default namespace is XMLNS.BASE or empty, |
|
|
|
# and if an ancestor was the same |
|
|
|
if n == "xmlns" and v in [ XMLNS.BASE, '' ] \ |
|
|
|
and ns_rendered.get('xmlns') in [ XMLNS.BASE, '', None ]: |
|
|
|
continue |
|
|
|
|
|
|
|
# "omit namespace node with local name xml, which defines |
|
|
|
# the xml prefix, if its string value is |
|
|
|
# http://www.w3.org/XML/1998/namespace." |
|
|
|
if n == "xmlns:xml" \ |
|
|
|
if n in ["xmlns:xml", "xml"] \ |
|
|
|
and v in [ 'http://www.w3.org/XML/1998/namespace' ]: |
|
|
|
continue |
|
|
|
|
|
|
|
# If different from parent, or parent didn't render |
|
|
|
# and if not exclusive, or this prefix is needed or |
|
|
|
# not suppressed |
|
|
|
if (v != pval or n not in ns_rendered) \ |
|
|
|
and (self.unsuppressedPrefixes is None or \ |
|
|
|
|
|
|
|
# If not previously rendered |
|
|
|
# and it's inclusive or utilized |
|
|
|
if (n,v) not in ns_rendered.items() \ |
|
|
|
and (_inclusive(self) or \ |
|
|
|
_utilized(n, node, other_attrs, self.unsuppressedPrefixes)): |
|
|
|
ns_to_render.append((n, v)) |
|
|
|
|
|
|
@@ -483,12 +354,15 @@ class _implementation: |
|
|
|
ns_to_render.sort(_sorter_ns) |
|
|
|
for n,v in ns_to_render: |
|
|
|
self._do_attr(n, v) |
|
|
|
ns_rendered.append(n) |
|
|
|
ns_rendered[n]=v #0417 |
|
|
|
|
|
|
|
# Add in the XML attributes (don't pass to children, since |
|
|
|
# we're rendering them), sort, and render. |
|
|
|
other_attrs.extend(xml_attrs) |
|
|
|
xml_attrs = [] |
|
|
|
# If exclusive or the parent is in the subset, add the local xml attributes |
|
|
|
# Else, add all local and ancestor xml attributes |
|
|
|
# Sort and render the attributes. |
|
|
|
if not _inclusive(self) or _in_subset(self.subset,node.parentNode): #0426 |
|
|
|
other_attrs.extend(xml_attrs_local.values()) |
|
|
|
else: |
|
|
|
other_attrs.extend(xml_attrs.values()) |
|
|
|
other_attrs.sort(_sorter) |
|
|
|
for a in other_attrs: |
|
|
|
self._do_attr(a.nodeName, a.value) |
|
|
@@ -520,17 +394,8 @@ def Canonicalize(node, output=None, **kw): |
|
|
|
prefixes that should be inherited. |
|
|
|
''' |
|
|
|
if output: |
|
|
|
if _implementation2 is None: |
|
|
|
_implementation(node, output.write, **kw) |
|
|
|
else: |
|
|
|
apply(_implementation2, (node, output.write), kw) |
|
|
|
apply(_implementation, (node, output.write), kw) |
|
|
|
else: |
|
|
|
s = StringIO.StringIO() |
|
|
|
if _implementation2 is None: |
|
|
|
_implementation(node, s.write, **kw) |
|
|
|
else: |
|
|
|
apply(_implementation2, (node, s.write), kw) |
|
|
|
apply(_implementation, (node, s.write), kw) |
|
|
|
return s.getvalue() |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': print _copyright |