Added fn:starts-with function.
authorFrederic Jolliton <frederic@jolliton.com>
Wed, 7 Sep 2005 21:45:23 +0000 (21:45 +0000)
committerFrederic Jolliton <frederic@jolliton.com>
Wed, 7 Sep 2005 21:45:23 +0000 (21:45 +0000)
git-archimport-id: frederic@jolliton.com--2005-main/tx--main--0.1--patch-9

xpathfn.py

index 5c8c308..3712cdd 100644 (file)
@@ -206,6 +206,13 @@ def oneAtomizedItem( sequence ) :
 
        return atomize( oneItem( sequence ) )
 
+def asStringOrStream( item ) :
+
+       if isNode( item ) :
+               return item.iterStringValue()
+       else :
+               return asString( item )
+
 #----------------------------------------------------------------------------
 
 def sequenceToBoolean( sequence ) :
@@ -227,6 +234,54 @@ def sequenceToBoolean( sequence ) :
 
 #----------------------------------------------------------------------------
 
+def _startsWith( s1 , s2 ) :
+
+       '''
+       Compare strings 's1' and 's2'. This function also accept iterators
+       returning string. This is usefull to compare two nodes without
+       first converting them to strings for performance reason.
+       '''
+
+       if isinstance( s1 , basestring ) :
+               if isinstance( s2 , basestring ) :
+                       return s1.startswith( s2 )
+               else :
+                       s1 = iterSingle( s1 )
+       elif isinstance( s2 , basestring ) :
+               s2 = iterSingle( s2 )
+
+       result = 0
+       d1 = ''
+       d2 = ''
+       while 1 :
+               if not d1 :
+                       try :
+                               d1 = s1.next()
+                       except StopIteration :
+                               d1 = ''
+               if not d2 :
+                       try :
+                               d2 = s2.next()
+                       except StopIteration :
+                               d2 = ''
+               if not d1 :
+                       if not d2 :
+                               r = True
+                       else :
+                               r = False
+                       break
+               elif not d2 :
+                       r = True
+                       break
+               m = min( len( d1 ) , len( d2 ) )
+               r = cmp( d1[ : m ] , d2[ : m ] )
+               if r != 0 :
+                       r = False
+                       break
+               d1 = d1[ m : ]
+               d2 = d2[ m : ]
+       return r
+
 def _compareString( s1 , s2 ) :
 
        '''
@@ -499,6 +554,16 @@ def fnName( context , arg = None ) :
                        return _EmptyString
        return Sequence( item.dmNodeName() )
 
+@registerFast( 'fn:starts-with' )
+def fnStartsWith( context , arg1 , arg2 , collation = None ) :
+
+       if collation is not None :
+               raise XError( 'FOCH0004' , 'Collation not supported' )
+       arg1 = zeroOrOneItem( arg1 )
+       arg2 = zeroOrOneItem( arg2 )
+       return _Boolean[ _startsWith( asStringOrStream( arg1 ) ,
+                                                                 asStringOrStream( arg2 ) ) ]
+
 #----------------------------------------------------------------------------
 
 @registerFast( 'op:is-same-node' )