Juan Zacarias has proposed merging lp:~zorba-coders/zorba/xqxq-url-resolver 
into lp:zorba/xqxq-module.

Requested reviews:
  Matthias Brantner (matthias-brantner)
  Chris Hillery (ceejatec)
Related bugs:
  Bug #903797 in Zorba: "XQXQ feature request: custom schema uri resolver"
  https://bugs.launchpad.net/zorba/+bug/903797

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/xqxq-url-resolver/+merge/123604
-- 
https://code.launchpad.net/~zorba-coders/zorba/xqxq-url-resolver/+merge/123604
Your team Zorba Coders is subscribed to branch lp:zorba/xqxq-module.
=== modified file 'src/xqxq.xq'
--- src/xqxq.xq	2012-04-11 09:50:05 +0000
+++ src/xqxq.xq	2012-09-10 17:28:35 +0000
@@ -56,6 +56,60 @@
   xs:anyURI external;
 
 (:~
+ : The function prepares a given XQuery program for execution.
+ : If the program was successfully compiled, the function returns an
+ : identifier as xs:anyURI. This URI can be passed to other functions
+ : of this module (e.g. to actually evaluate the program). The URI
+ : is opaque and its lilfetime is bound by the lifetime of the XQuery
+ : program that invoked this function. Further reference or uses
+ : of the identifier lead to unexpected results.
+ : 
+ : Important notes regarding the second parameter of the function.
+ :
+ : The second parameter is the xs:QName of a function describing the new url
+ : resolver. The url resolver function described must recive 2 parameters. 
+ : A $namespace as xs:string that will contain the url to be resolved.
+ : A $data-entity as xs:string that will contain the type of resolving needed
+ : this can be 2 values "module" and "schema".
+ : The function described must return an empty sequence when the specified $namespace
+ : or $data-entity are not the ones to be resolved.
+ :
+ : Example:
+ :   
+ : declare namespace resolver = 'http://www.zorba-xquery.com/modules/xqxq/url-resolver';
+ : declare function resolver:url-resolver($namespace as xs:string, $entity as xs:string)
+ : {
+ :  if($namespace = 'http://test.xq')
+ :  then "module namespace test = 'http://test'; declare function test:foo(){'foo'};"
+ :  else ()
+ : };
+ :
+ : The url resolver function's namespace, function's name, and parameters' naming are
+ : not restricted by the module.
+ :
+ : The url resolver function's return type is not restricted, it could be a string, a sequence,
+ : a node, etc. All the outputs types are to be serialized as a string.
+ :
+ : Successfully prepared queries need to be deleted by passing the resulting
+ : identifier to the xqxq:delete-query function of this module.
+ :
+ : @param $main-module-text the XQuery program that should be prepared.
+ :   The program needs to be a XQuery main module.
+ :
+ : @param $function the xs:QName of a function that is going to be used
+ :   as a url resolver.
+ :
+ : @return an identifier for the compiled program that can be passed
+ :   as arguments to other functions of this module.
+ :
+ : @error any (static or type) error that may be raised during the compilation
+ : of the query. For example, err:XPST0003 if the given XQuery program could
+ : not be parsed.
+ :)
+declare %an:sequential function xqxq:prepare-main-module($main-module-text as xs:string, $function as xs:QName) as 
+  xs:anyURI external;
+
+(:~
  : This function compiles a given XQuery library module. It can be used
  : to compile-check a module. 
  :

=== modified file 'src/xqxq.xq.src/xqxq.cpp'
--- src/xqxq.xq.src/xqxq.cpp	2011-11-30 21:57:52 +0000
+++ src/xqxq.xq.src/xqxq.cpp	2012-09-10 17:28:35 +0000
@@ -226,6 +226,80 @@
 
   /*******************************************************************************************
   *******************************************************************************************/
+  static void streamReleaser(std::istream* aStream)
+  {
+    delete aStream;
+  }  
+  
+  Resource*
+    PrepareMainModuleFunction::XQXQURLResolver::resolveURL(
+    const String& aUrl,
+    EntityData const* aEntityData)
+  { 
+    //Create entityData string to send to the new url resolver
+    String lDataKind;
+    switch (aEntityData->getKind())
+    {
+      case EntityData::SCHEMA:
+        lDataKind = "schema";
+        break;
+      case EntityData::MODULE:
+        lDataKind = "module";
+        break;
+      default:
+        break;
+    }
+
+    //construct the arguments for the url resolver
+    std::vector<ItemSequence_t> lArgs;
+    ItemSequence_t lSeq1 = new SingletonItemSequence(XQXQModule::getItemFactory()->createString(aUrl));
+    ItemSequence_t lSeq2 = new SingletonItemSequence(XQXQModule::getItemFactory()->createString(lDataKind));
+    lArgs.push_back(lSeq1);
+    lArgs.push_back(lSeq2);
+
+    //invoke the function using the arguments generated and the QName of the function
+    ItemSequence_t lResult = theCtx->invoke(theFunction, lArgs);
+
+    //Check if the result is an empty sequence by creating an Iterator, this is cheaper than serializing the result
+    //and then checking if it was empty.
+    Iterator_t lIter = lResult->getIterator();
+    Item lItem;
+    lIter->open();
+    lIter->next(lItem);
+    lIter->close();
+    if (lItem.isNull())
+      return NULL;
+
+    //Serialize resulting sequence of the resolver
+    Zorba_SerializerOptions_t lOpt;
+    if (lItem.isNode())
+      lOpt.ser_method = ZORBA_SERIALIZATION_METHOD_XML;
+    else
+      lOpt.ser_method = ZORBA_SERIALIZATION_METHOD_TEXT;
+    lOpt.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES;
+    Serializer_t lSer = Serializer::createSerializer(lOpt);
+    std::stringstream lSerResult;
+    lSer->serialize(lResult, lSerResult);
+
+    //return resource
+    return StreamResource::create(new std::istringstream(lSerResult.str()), &streamReleaser);
+
+    /*
+    // we have only one module
+       if (aEntityData->getKind() == EntityData::MODULE &&
+         aUrl == "http://www.zorba-xquery.com/modules/xqxq/test";) 
+       {
+         return StreamResource::create
+           (new std::istringstream
+             ("module namespace test = 'http://www.zorba-xquery.com/modules/xqxq/test'; "
+              "declare function test:foo() { 'foo' };"), &streamReleaser);
+       }
+       else {
+         return NULL;
+       }
+    */
+  }
+
   zorba::ItemSequence_t
     PrepareMainModuleFunction::evaluate(
       const Arguments_t& aArgs,
@@ -233,6 +307,7 @@
       const zorba::DynamicContext* aDctx) const 
   {
     DynamicContext* lDynCtx = const_cast<DynamicContext*>(aDctx);
+    StaticContext_t lSctxChild = aSctx->createChildContext();
    
     QueryMap* lQueryMap;
     if(!(lQueryMap = dynamic_cast<QueryMap*>(lDynCtx->getExternalFunctionParameter("xqxqQueryMap"))))
@@ -247,9 +322,24 @@
     
     XQuery_t lQuery;
     
+    StaticContext_t ltempSctx = lZorba->createStaticContext();
+    XQXQURLResolver* lResolver = NULL;
+
+    if ( aArgs.size() > 1 )
+    {
+      Item lFunctionQname = getItemArgument(aArgs, 1);
+      
+      if (lSctxChild->containsFunction(lFunctionQname.getNamespace(), lFunctionQname.getLocalName(), 2))
+        {
+          lResolver = new XQXQURLResolver(lFunctionQname, lSctxChild);      
+          ltempSctx->registerURLResolver(lResolver);
+        }
+
+    }
+
     try
     {
-      lQuery = lZorba->compileQuery(lQueryString);
+      lQuery = lZorba->compileQuery(lQueryString, ltempSctx);
     }
     catch (XQueryException& xe)
     {
@@ -273,6 +363,10 @@
     String lUUID = getUUID();
     
     lQueryMap->storeQuery(lUUID, lQuery);
+    
+    
+    if (lResolver)
+      delete lResolver;
 
     return ItemSequence_t(new SingletonItemSequence(XQXQModule::getItemFactory()->createAnyURI(lUUID)));
   }

=== modified file 'src/xqxq.xq.src/xqxq.h'
--- src/xqxq.xq.src/xqxq.h	2011-11-28 23:55:59 +0000
+++ src/xqxq.xq.src/xqxq.h	2012-09-10 17:28:35 +0000
@@ -49,6 +49,7 @@
 
   };
 
+
   class QueryMap : public ExternalFunctionParameter{
     private:
       typedef std::map<String, XQuery_t> QueryMap_t;
@@ -117,7 +118,7 @@
     public:
       PrepareMainModuleFunction(const XQXQModule* aModule) : XQXQFunction(aModule) {}
 
-      virtual ~PrepareMainModuleFunction(){}
+      virtual ~PrepareMainModuleFunction(){  }
       
       virtual zorba::String
         getLocalName() const { return "prepare-main-module"; }
@@ -127,12 +128,29 @@
                  const zorba::StaticContext*,
                  const zorba::DynamicContext*) const;
 
-    protected:
-       static String
-         getUUID();
-
-       static String
-         S4();
+      protected:
+
+      class XQXQURLResolver : public URLResolver
+      {
+        protected:
+        Item theFunction;
+        StaticContext_t theCtx;
+
+        public:
+        XQXQURLResolver(Item& aFunction, StaticContext_t& aSctx) : URLResolver(), theFunction(aFunction), theCtx(aSctx) {}
+        
+        virtual ~XQXQURLResolver(){ }
+      
+        virtual Resource* resolveURL(const String& aUrl,
+          EntityData const* aEntityData);
+
+      };
+
+      static String
+        getUUID();
+
+      static String
+        S4();
 
   };
 

=== added file 'test/ExpQueryResults/xqxq/url-module-resolver.xml.res'
--- test/ExpQueryResults/xqxq/url-module-resolver.xml.res	1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/xqxq/url-module-resolver.xml.res	2012-09-10 17:28:35 +0000
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+foo

=== added file 'test/ExpQueryResults/xqxq/url-schema-module-resolver.xml.res'
--- test/ExpQueryResults/xqxq/url-schema-module-resolver.xml.res	1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/xqxq/url-schema-module-resolver.xml.res	2012-09-10 17:28:35 +0000
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test:test xmlns:test="http://test";><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>

=== added file 'test/ExpQueryResults/xqxq/url-schema-resolver.xml.res'
--- test/ExpQueryResults/xqxq/url-schema-resolver.xml.res	1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/xqxq/url-schema-resolver.xml.res	2012-09-10 17:28:35 +0000
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test:test xmlns:test="http://test";><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>

=== added file 'test/ExpQueryResults/xqxq/url-schema-resolver2.xml.res'
--- test/ExpQueryResults/xqxq/url-schema-resolver2.xml.res	1970-01-01 00:00:00 +0000
+++ test/ExpQueryResults/xqxq/url-schema-resolver2.xml.res	2012-09-10 17:28:35 +0000
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test:test xmlns:test="http://test";><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>

=== added file 'test/Queries/xqxq/test.xsd'
--- test/Queries/xqxq/test.xsd	1970-01-01 00:00:00 +0000
+++ test/Queries/xqxq/test.xsd	2012-09-10 17:28:35 +0000
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema";
+  targetNamespace="http://test";
+  xmlns="http://test";
+  elementFormDefault="qualified">
+  <xs:element name="test">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="subtest" type="xs:string"/>
+        <xs:element name="subtest2" type="xs:string"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>                                                               
\ No newline at end of file

=== added file 'test/Queries/xqxq/url-module-resolver.xq'
--- test/Queries/xqxq/url-module-resolver.xq	1970-01-01 00:00:00 +0000
+++ test/Queries/xqxq/url-module-resolver.xq	2012-09-10 17:28:35 +0000
@@ -0,0 +1,11 @@
+import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';
+
+declare namespace resolver = 'http://www.zorba-xquery.com/modules/xqxq/url-resolver';
+declare function resolver:url-resolver($namespace as xs:string, $entity as xs:string) {
+  if($namespace = 'http://test.xq')
+  then "module namespace test = 'http://test'; declare function test:foo(){'foo'};"
+  else ()
+};
+
+variable $queryID := xqxq:prepare-main-module("import module namespace test = 'http://test'; test:foo()", fn:QName('http://www.zorba-xquery.com/modules/xqxq/url-resolver', 'resolver:url-resolver'));
+xqxq:evaluate($queryID)                                                                             

=== added file 'test/Queries/xqxq/url-schema-module-resolver.xq'
--- test/Queries/xqxq/url-schema-module-resolver.xq	1970-01-01 00:00:00 +0000
+++ test/Queries/xqxq/url-schema-module-resolver.xq	2012-09-10 17:28:35 +0000
@@ -0,0 +1,24 @@
+import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';
+
+declare namespace resolver = 'http://www.zorba-xquery.com/modules/xqxq/url-resolver';
+declare function resolver:url-resolver($namespace as xs:string, $entity as xs:string){
+  if($entity = 'module')
+  then
+    if($namespace = 'http://test')
+    then
+      "module namespace test = 'http://test'; declare function test:foo(){<test:test><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>};"
+    else
+      ()
+  else if ($entity = 'schema')
+    then
+      if($namespace = 'http://test')
+      then
+        doc('test.xsd')
+      else
+        ()
+    else
+      ()
+};
+
+variable $queryID := xqxq:prepare-main-module("import module namespace modtest = 'http://test'; import schema namespace test = 'http://test'; validate{let $x := modtest:foo() return $x}", fn:QName('http://www.zorba-xquery.com/modules/xqxq/url-resolver', 'resolver:url-resolver'));
+xqxq:evaluate($queryID)                                                                             
\ No newline at end of file

=== added file 'test/Queries/xqxq/url-schema-resolver.xq'
--- test/Queries/xqxq/url-schema-resolver.xq	1970-01-01 00:00:00 +0000
+++ test/Queries/xqxq/url-schema-resolver.xq	2012-09-10 17:28:35 +0000
@@ -0,0 +1,13 @@
+import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';
+
+declare namespace resolver = 'http://www.zorba-xquery.com/modules/xqxq/url-resolver';
+declare function resolver:url-resolver($namespace as xs:string, $entity as xs:string) {
+  if($namespace = 'http://test' and $entity = 'schema')
+  then 
+    doc('test.xsd')
+  else 
+    ()
+};
+
+variable $queryID := xqxq:prepare-main-module("import schema namespace test = 'http://test'; validate {<test:test><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>}", fn:QName('http://www.zorba-xquery.com/modules/xqxq/url-resolver', 'resolver:url-resolver'));
+xqxq:evaluate($queryID)                                                                             

=== added file 'test/Queries/xqxq/url-schema-resolver2.xq'
--- test/Queries/xqxq/url-schema-resolver2.xq	1970-01-01 00:00:00 +0000
+++ test/Queries/xqxq/url-schema-resolver2.xq	2012-09-10 17:28:35 +0000
@@ -0,0 +1,23 @@
+import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq';
+
+import module namespace ddl =
+    "http://www.zorba-xquery.com/modules/store/dynamic/collections/w3c/ddl";;
+import module namespace dml =
+    "http://www.zorba-xquery.com/modules/store/dynamic/collections/w3c/dml";;
+
+declare namespace resolver = 'http://www.zorba-xquery.com/modules/xqxq/url-resolver';
+declare function resolver:url-resolver($namespace as xs:string, $entity as xs:string) {
+  if ($entity = 'schema')
+  then
+    dml:collection("http://www.zorba-xquery.com/modules/xqxq";)//xs:schema[@targetNamespace=$namespace]
+  else
+    ()
+};
+
+declare variable $coll := "http://www.zorba-xquery.com/modules/xqxq";;
+declare variable $schema := doc("test.xsd");
+ddl:create($coll);
+
+dml:apply-insert-nodes-first($coll, $schema);
+variable $query-key := xqxq:prepare-main-module("import schema namespace test = 'http://test'; validate {<test:test><test:subtest>a</test:subtest><test:subtest2>a</test:subtest2></test:test>}", fn:QName('http://www.zorba-xquery.com/modules/xqxq/url-resolver', 'resolver:url-resolver'));
+xqxq:evaluate($query-key)                                                
\ No newline at end of file

-- 
Mailing list: https://launchpad.net/~zorba-coders
Post to     : zorba-coders@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zorba-coders
More help   : https://help.launchpad.net/ListHelp

Reply via email to