Clone attributes as needed. Added Node.xpath, Node.match.
authorFrederic Jolliton <frederic@jolliton.com>
Tue, 13 Sep 2005 07:11:21 +0000 (07:11 +0000)
committerFrederic Jolliton <frederic@jolliton.com>
Tue, 13 Sep 2005 07:11:21 +0000 (07:11 +0000)
 * Attributes are cloned when inserted in a tree if they're already part
   of another tree.

 * Added Node.xpath as canonical name to query a tree with a XPath
   expression (and with [] and / operator overloaded to call it.)

 * Added Node.match to test node against a XSLT pattern.
git-archimport-id: frederic@jolliton.com--2005-main/tx--main--0.1--patch-42

nodes.py

index fabbee6..c66dac0 100644 (file)
--- a/nodes.py
+++ b/nodes.py
@@ -70,6 +70,18 @@ def _combineAdjacentText( nodes ) :
                        lastTextNode = None
        return tuple( result )
 
+def _processAttributes( attributes ) :
+
+       '''Clone attributes that are already part of another tree (which have
+       a parent).'''
+
+       result = []
+       for attribute in attributes :
+               if attribute.parent is not None :
+                       attribute = attribute.clone()
+               result.append( attribute )
+       return tuple( result )
+
 def _chainNodes( nodes , parent ) :
 
        '''Update parent, prev and next reference for nodes in 'nodes'.  The
@@ -268,14 +280,18 @@ class Node( object ) :
                        raise NodeError( 'prev reference is already set' )
                self.prev = node
 
+       def xpath( self , path ) :
+
+               import xpath
+               xpathObject = xpath.XPath( path )
+               return xpathObject.eval( self )
+
        def __getitem__( self , path ) :
 
                if not isinstance( path , basestring ) :
                        return super( Node , self ).__getitem__( path )
                else :
-                       import xpath
-                       xpathObject = xpath.XPath( path )
-                       return xpathObject.eval( self )
+                       return self.xpath( path )
 
        # Abusing operator overloading
        def __div__( self , path ) :
@@ -286,6 +302,11 @@ class Node( object ) :
 
                raise NotImplementedError
 
+       def match( self , pat ) :
+
+               import pattern
+               return pattern.test( self , pat )
+
        def __cmp__( self , other ) :
 
                if other is self :
@@ -528,7 +549,7 @@ class Element( Node ) :
 
                self.name = name
                self.children = children
-               self.attributes = tuple( attributes )
+               self.attributes = _processAttributes( attributes )
 
                _chainNodes( self.children , self )
                _chainNodes( self.attributes , self )