[XML-SIG] femto-dom?

Rich Salz rsalz@zolera.com
Fri, 22 Jun 2001 21:11:54 -0400


This is a multi-part message in MIME format.
--------------8BE50EE5E03BF832881B3001
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

We needed a way to create XML fragments that we could then output within
other documents. The DOM API is way too heavyweight.  So we took the
Canonicalize() routine, looked at the attributes it uses, and created
this femto-DOM.

Is there any interest in this?  If so I'll document it (where?) and
check it in.
	/r$
--------------8BE50EE5E03BF832881B3001
Content-Type: text/plain; charset=us-ascii;
 name="simplenode.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="simplenode.py"

#! /usr/bin/env python
'''Simple DOM node builder.
'''

from xml.dom import Node
from xml.ns import XMLNS

def _splitname(name):
    '''Split a name, returning prefix, localname, qualifiedname.
    '''
    i = name.find(':')
    if i == -1: return '', name, name
    return name[:i], name[i + 1:], name

def _initattrs(n, type):
    '''Set the initial node attributes.
    '''
    n.attributes = []
    n.childNodes = []
    n.nodeType = type
    n.parentNode = None
    n.namespaceURI = ''

class SimpleContentNode:
    '''A CDATA, TEXT, or COMMENT node.
    '''
    def __init__(self, type, text):
	_initattrs(self, type)
	self.data = text

class SimplePINode:
    '''A PI node.
    '''
    def __init__(self, name, value):
	_initattrs(self, Node.PROCESSING_INSTRUCTION_NODE)
	self.name, self.value, self.nodeValue = name, value, value

class SimpleAttributeNode:
    '''An element attribute node.
    '''
    def __init__(self, name, value):
	_initattrs(self, Node.ATTRIBUTE_NODE)
	self.value, self.nodeValue = value, value
	self.prefix, self.localName, self.nodeName = _splitname(name)

class SimpleElementNode:
    '''An element.  Might have children, text, and attributes.
    '''
    def __init__(self, name, nsdict = None, newline = 1):
	if nsdict:
	    self.nsdict = nsdict.copy()
	else:
	    self.nsdict = {}
	_initattrs(self, Node.ELEMENT_NODE)
	self.prefix, self.localName, self.nodeName = _splitname(name)
	self.namespaceURI = self.nsdict.get(self.prefix, None)
	for k,v in self.nsdict.items():
	    self.AddNSAttr(k, v)
	if newline: self.AddText('\n')

    def nslookup(self, key):
	n = self
	while n:
	    if n.nsdict.has_key(key): return n.nsdict[key]
	    n = n.parentNode
	raise KeyError, "namespace prefix %s not found" % key

    def AddAttr(self, name, value):
	n = SimpleAttributeNode(name, value)
	n.parentNode = self
	if not n.prefix:
	    n.namespaceURI = None
	else:
	    n.namespaceURI = self.nslookup(n.prefix)
	self.attributes.append(n)
	return self

    def AddNSAttr(self, prefix, value):
	if prefix:
	    n = SimpleAttributeNode("xmlns:" + prefix, value)
	else:
	    n = SimpleAttributeNode("xmlns", value)
	n.parentNode, n.namespaceURI = self, XMLNS.BASE
	self.attributes.append(n)
	self.nsdict[prefix] = value
	return self

    def AddDefaultNSAttr(self, value):
	return self.AddNSAttr('', value)

    def AddChild(self, n):
	n.parentNode = self
	if n.namespaceURI == None: n.namespaceURI = self.namespaceURI
	self.childNodes.append(n)
	return self

    def AddText(self, text):
	n = SimpleContentNode(Node.TEXT_NODE, text)
	return self.AddChild(n)

    def AddCDATA(self, text):
	n = SimpleContentNode(Node.CDATA_SECTION_NODE, text)
	return self.AddChild(n)

    def AddComment(self, text):
	n = SimpleContentNode(Node.COMMENT_NODE, text)
	return self.AddChild(n)

    def AddPI(self, name, value):
	n = SimplePINode(name, value)
	return self.AddChild(n)
	return self

    def AddElement(self, name, nsdict = None, newline = 1):
	n = SimpleElementNode(name, nsdict, newline)
	self.AddChild(n)
	return n


if __name__ == '__main__':
    e = SimpleElementNode('z', {'': 'uri:example.com', 'q':'q-namespace'})

    n = e.AddElement('zchild')
    n.AddNSAttr('d', 'd-uri')
    n.AddAttr('foo', 'foo-value')
    n.AddText('some text for d\n')
    n.AddElement('d:k2').AddText('innermost txt\n')

    e.AddElement('q:e-child-2').AddComment('This is a comment')
    e.AddText('\n')
    e.AddElement('ll:foo', { 'll': 'example.org'})
    e.AddAttr('eattr', '''eat at joe's''')

    from xml.dom.ext import Canonicalize
    print Canonicalize(e, comments=1)

--------------8BE50EE5E03BF832881B3001--