Added missing in-scope-schema-types function declaration.

(:
 : Copyright 2006-2009 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)

(:~
 : Intospection Module for the Static Context components.
 :
 : @see http://www.w3.org/TR/xquery/#id-xq-static-context-components
 :
 : @version 1.0
 :)

module namespace sctx = "http://www.zorba-xquery.com/modules/introspection/sctx";

(:~
 : The function returns true if a collection with the given QName has been created.
 :
 : @param $name The QName of the collection that is being checked.
 : @return true if the collection has been created and false otherwise.
 :)
declare function sctx:is-declared-collection($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a sequence of QNames representing the collections that have
 : been previously created. The sequence will be empty if there are no collections.
 :
 : @return A sequence of QNames, one for each created collection, or an emtpy sequence.
 :)
declare function sctx:declared-collections() as xs:QName* external;

(:~
 : The function returns true if an index with the given QName has been declared.
 :
 : @param $name The QName of the index that is being checked.
 : @return true if the index has been declared and false otherwise.
 :)
declare function sctx:is-declared-index($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a sequence of QNames representing the indexes that have
 : been previously created. The sequence will be empty if there are no indexes.
 :
 : @return A sequence of QNames, one for each created index, or an empty
 : sequence if none exist.
 :)
declare function sctx:declared-indexes() as xs:QName* external;

(:~
 : The function returns a sequence of QNames representing the integrity
 : constraints that have been declared, as described by the Zorba Data
 : Definition Language extension. The sequence will be empty if there are no
 : integrity constraints.
 :
 : @return A sequence of QNames, one for each declared integrity constraint,
 : or an empty sequence if none are declared.
 :)
declare function sctx:declared-integrity-constraints() as xs:QName* external;

(:~
 : The function checks if an integrity constraint with the given QName has
 : been declared.
 :
 : @param $name The QName of the constraint that is being checked.
 : @return true if the integrity constraint has been declared and false
 : otherwise.
 :)
declare function sctx:is-declared-integrity-constraint($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a list of known statically known namespaces as prefixes
 : (fn, xml, xs, xsi, etc).
 : @return A sequence of xs:strings, one for each known namespace prefix.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-namespaces
 :)
declare function sctx:statically-known-namespaces() as xs:string* external;

(:~
 : For any statically know namespace prefix, the bound URI can be retreived
 : with the statically-known-namespace-bindings() function.
 :
 : @param $prefix The prefix of the known namespace, for which the bound URI
 : is being requested.
 : @return The URI bound to the prefix is returned, or an empty sequence if
 : the prefix is not known.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-namespaces
 :)
declare function sctx:statically-known-namespace-binding($prefix as xs:string) as xs:string? external;

(:~
 : The function returns the URI of the default function namespace.
 :
 : @return The URI of the of the default function namespace.
 :
 : @see http://www.w3.org/TR/xquery/#dt-def-fn-ns
 :)
declare function sctx:default-function-namespace() as xs:string
{
  sctx:statically-known-namespace-binding("fn")
};

(:~
 : The function returns the base URI.
 :
 : @return The base URI.
 :
 : @see http://www.w3.org/TR/xquery/#dt-base-uri
 :)
declare function sctx:base-uri() as xs:string?
{
  fn:static-base-uri()
};

(:~
 : The function returns the statically known default collection type. This
 : is the type of the sequence of nodes that would result from calling the
 : fn:collection function with no arguments.
 :
 : @return The type of the default collection.
 :
 : @see http://www.w3.org/TR/xquery/#dt-known-default-collection
 :)
declare function sctx:default-collection-type() as xs:string external;

(:~
 : The function return a sequence of QNames identifying declared variables
 : from the static context.
 :
 : @return A sequence of QNames, one for each variable.
 :
 : @see http://www.w3.org/TR/xquery/#dt-in-scope-variables
 :)
declare function sctx:in-scope-variables() as xs:QName* external;

(:~
 : The function returns a sequence of QNames identifying in-scope schema types,
 : including all the predefined schema types and all definitions found in
 : imported schemas.
 :
 : @return A sequence of QNames, one for each defined type.
 :
 : @see http://www.w3.org/TR/xquery/#dt-is-types
 :)
declare function sctx:in-scope-schema-types() as xs:QName* external;

(:~
 : The function return a sequence of QNames identifying declared elements
 : in the imported schemas.
 :
 : @return A sequence of QNames, one for each declared element.
 :
 : @see http://www.w3.org/TR/xquery/#dt-is-elems
 :)
declare function sctx:in-scope-element-declarations() as xs:QName* external;

(:~
 : The function return a sequence of QNames identifying declared attributes
 : in the imported schemas.
 :
 : @return A sequence of QNames, one for each attribute.
 :
 : @see http://www.w3.org/TR/xquery/#dt-is-attrs
 :)
declare function sctx:in-scope-attribute-declarations() as xs:QName* external;

(:~
 : The function returns a sequence of QNames identifying declared in-scope
 : schema element groups.
 :
 : @return A sequence of QNames, one for each element group.
 :)
declare function sctx:in-scope-element-groups() as xs:QName* external;

(:~
 : The function returns a sequence of QNames identifying declared in-scope
 : schema attribute groups.
 :
 : @return A sequence of QNames, one for each attribute group.
 :)
declare function sctx:in-scope-attribute-groups() as xs:QName* external;

(:~
 : The function returns a sequence containing the QNames of all defined
 : functions, which are available to be called from within an expression.
 :
 : @return A sequence for QNames identifying all functions.
 :
 : @see http://www.w3.org/TR/xquery/#dt-function-signature
 :)
declare function sctx:function-names() as xs:QName* external;

(:~
 : The function returns the number of arguments the given XQuery $function
 : takes.
 :
 : @param $function A QName identifying a function.
 : @return A sequence of zero or more integers, one for each overloaded version
 : of the given function. An empty sequence is returned if the function is not
 : defined.
 :
 : @see http://www.w3.org/TR/xquery/#dt-function-signature
 :)
declare function sctx:function-arguments-count($function as xs:QName) as xs:int* external;

(:~
 : The function returns true or false depending on whether rules for
 : compatibility with XPath 1.0 are in effect. XQuery set the value
 : of this component to false.
 :
 : @return The function should return false
 :
 : @see http://www.w3.org/TR/xquery/#dt-xpath-compat-mode
 :)
declare function sctx:xpath10-compatibility-mode() as xs:boolean external;

(:~
 : The function returns one of statically known collations that is used by
 : functions and operators for comparing and ordering values of type xs:string
 : or xs:anyURI when no explicit collation is specified.
 :
 : @return The collations that is used by default.
 :
 : @see http://www.w3.org/TR/xquery/#dt-def-collation
 :)
declare function sctx:default-collation() as xs:string
{
  fn:default-collation()
};

(:~
  : The function returns a sequence that contains the URIs of all statically known documents.
  :
  : @return The sequence of document URIs.
  :
  : @see http://www.w3.org/TR/xquery/#dt-known-docs
  :)
declare function sctx:statically-known-documents() as xs:anyURI* external;

(:~
  : For the given document, the function returns the static type of its root node.
  :
  : @param $document An URI of a document.
  : @return The static type of the given document.
  :
  : @see http://www.w3.org/TR/xquery/#dt-known-docs
  :)
declare function sctx:statically-known-document-type($document as xs:string) as xs:QName external;

(:~
 : The function returns a sequence that contains the statically known collations.
 :
 : @return The sequence of collations.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-collations
 :)
declare function sctx:statically-known-collations() as xs:anyURI* external;

(:~
 : The function returns the static context construction mode of element and
 : document nodes.
 :
 : @return Either "preserve" or "strip", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-construction-mode
 :)
declare function sctx:construction-mode() as xs:string external;

(:~
 : The function returns the static context ordering mode, which affects the
 : ordering of the result sequences returned by certain expressions.
 :
 : @return Either "ordered" or "unordered", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-ordering-mode
 :)
declare function sctx:ordering-mode() as xs:string external;

(:~
 : The function returns the static context component which controls the
 : processing of empty sequences and NaN values as ordering keys in an order
 : by clause in a FLWOR expression.
 :
 : @return Either "greatest" or "least", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-default-empty-order
 :)
declare function sctx:default-order() as xs:string external;

(:~
 : The function returns the static context component which contrls the
 : processing of boundary whitespace by direct element constructors.
 :
 : @return Either "preserve" or "strip", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-boundary-space-policy
 :)
declare function sctx:boundary-space-policy() as xs:string external;

(:~
 : The function returns the static context components which control the
 : the namespace bindings that are assigned when an existing element node
 : is copied by an element constructor
 :
 : @return A sequence containing exactly two strings, of which the first
 : has a value of either "preserve" or "no-preserve" and the second a value
 : of either "inherit" or "no-inherit".
 :
 : @see http://www.w3.org/TR/xquery/#dt-copy-namespaces-mode
 :)
declare function sctx:copy-namespaces-mode() as xs:string+ external;

(:
 : Copyright 2006-2009 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)

(:~
 : Intospection Module for the Static Context components.
 :
 : @see http://www.w3.org/TR/xquery/#id-xq-static-context-components
 :
 : @version 1.0
 :)

module namespace sctx = "http://www.zorba-xquery.com/modules/introspection/sctx";

(:~
 : The function returns true if a collection with the given QName has been created.
 :
 : @param $name The QName of the collection that is being checked.
 : @return true if the collection has been created and false otherwise.
 :)
declare function sctx:is-declared-collection($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a sequence of QNames representing the collections that have
 : been previously created. The sequence will be empty if there are no collections.
 :
 : @return A sequence of QNames, one for each created collection, or an emtpy sequence.
 :)
declare function sctx:declared-collections() as xs:QName* external;

(:~
 : The function returns true if an index with the given QName has been declared.
 :
 : @param $name The QName of the index that is being checked.
 : @return true if the index has been declared and false otherwise.
 :)
declare function sctx:is-declared-index($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a sequence of QNames representing the indexes that have
 : been previously created. The sequence will be empty if there are no indexes.
 :
 : @return A sequence of QNames, one for each created index, or an empty
 : sequence if none exist.
 :)
declare function sctx:declared-indexes() as xs:QName* external;

(:~
 : The function returns a sequence of QNames representing the integrity
 : constraints that have been declared, as described by the Zorba Data
 : Definition Language extension. The sequence will be empty if there are no
 : integrity constraints.
 :
 : @return A sequence of QNames, one for each declared integrity constraint,
 : or an empty sequence if none are declared.
 :)
declare function sctx:declared-integrity-constraints() as xs:QName* external;

(:~
 : The function checks if an integrity constraint with the given QName has
 : been declared.
 :
 : @param $name The QName of the constraint that is being checked.
 : @return true if the integrity constraint has been declared and false
 : otherwise.
 :)
declare function sctx:is-declared-integrity-constraint($name as xs:QName) as xs:boolean external;

(:~
 : The function returns a list of known statically known namespaces as prefixes
 : (fn, xml, xs, xsi, etc).
 : @return A sequence of xs:strings, one for each known namespace prefix.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-namespaces
 :)
declare function sctx:statically-known-namespaces() as xs:string* external;

(:~
 : For any statically know namespace prefix, the bound URI can be retreived
 : with the statically-known-namespace-bindings() function.
 :
 : @param $prefix The prefix of the known namespace, for which the bound URI
 : is being requested.
 : @return The URI bound to the prefix is returned, or an empty sequence if
 : the prefix is not known.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-namespaces
 :)
declare function sctx:statically-known-namespace-binding($prefix as xs:string) as xs:string? external;

(:~
 : The function returns the URI of the default function namespace.
 :
 : @return The URI of the of the default function namespace.
 :
 : @see http://www.w3.org/TR/xquery/#dt-def-fn-ns
 :)
declare function sctx:default-function-namespace() as xs:string
{
  sctx:statically-known-namespace-binding("fn")
};

(:~
 : The function returns the base URI.
 :
 : @return The base URI.
 :
 : @see http://www.w3.org/TR/xquery/#dt-base-uri
 :)
declare function sctx:base-uri() as xs:string?
{
  fn:static-base-uri()
};

(:~
 : The function returns the statically known default collection type. This
 : is the type of the sequence of nodes that would result from calling the
 : fn:collection function with no arguments.
 :
 : @return The type of the default collection.
 :
 : @see http://www.w3.org/TR/xquery/#dt-known-default-collection
 :)
declare function sctx:default-collection-type() as xs:string external;

(:~
 : The function return a sequence of QNames identifying declared variables
 : from the static context.
 :
 : @return A sequence of QNames, one for each variable.
 :
 : @see http://www.w3.org/TR/xquery/#dt-in-scope-variables
 :)
declare function sctx:in-scope-variables() as xs:QName* external;

(:~
 : The function return a sequence of QNames identifying declared elements
 : in the imported schemas.
 :
 : @return A sequence of QNames, one for each declared element.
 :
 : @see http://www.w3.org/TR/xquery/#dt-is-elems
 :)
declare function sctx:in-scope-element-declarations() as xs:QName* external;

(:~
 : The function return a sequence of QNames identifying declared attributes
 : in the imported schemas.
 :
 : @return A sequence of QNames, one for each attribute.
 :
 : @see http://www.w3.org/TR/xquery/#dt-is-attrs
 :)
declare function sctx:in-scope-attribute-declarations() as xs:QName* external;

(:~
 : The function returns a sequence of QNames identifying declared in-scope
 : schema element groups.
 :
 : @return A sequence of QNames, one for each element group.
 :)
declare function sctx:in-scope-element-groups() as xs:QName* external;

(:~
 : The function returns a sequence of QNames identifying declared in-scope
 : schema attribute groups.
 :
 : @return A sequence of QNames, one for each attribute group.
 :)
declare function sctx:in-scope-attribute-groups() as xs:QName* external;

(:~
 : The function returns a sequence containing the QNames of all defined
 : functions, which are available to be called from within an expression.
 :
 : @return A sequence for QNames identifying all functions.
 :
 : @see http://www.w3.org/TR/xquery/#dt-function-signature
 :)
declare function sctx:function-names() as xs:QName* external;

(:~
 : The function returns the number of arguments the given XQuery $function
 : takes.
 :
 : @param $function A QName identifying a function.
 : @return A sequence of zero or more integers, one for each overloaded version
 : of the given function. An empty sequence is returned if the function is not
 : defined.
 :
 : @see http://www.w3.org/TR/xquery/#dt-function-signature
 :)
declare function sctx:function-arguments-count($function as xs:QName) as xs:int* external;

(:~
 : The function returns true or false depending on whether rules for
 : compatibility with XPath 1.0 are in effect. XQuery set the value
 : of this component to false.
 :
 : @return The function should return false
 :
 : @see http://www.w3.org/TR/xquery/#dt-xpath-compat-mode
 :)
declare function sctx:xpath10-compatibility-mode() as xs:boolean external;

(:~
 : The function returns one of statically known collations that is used by
 : functions and operators for comparing and ordering values of type xs:string
 : or xs:anyURI when no explicit collation is specified.
 :
 : @return The collations that is used by default.
 :
 : @see http://www.w3.org/TR/xquery/#dt-def-collation
 :)
declare function sctx:default-collation() as xs:string
{
  fn:default-collation()
};

(:~
  : The function returns a sequence that contains the URIs of all statically known documents.
  :
  : @return The sequence of document URIs.
  :
  : @see http://www.w3.org/TR/xquery/#dt-known-docs
  :)
declare function sctx:statically-known-documents() as xs:anyURI* external;

(:~
  : For the given document, the function returns the static type of its root node.
  :
  : @param $document An URI of a document.
  : @return The static type of the given document.
  :
  : @see http://www.w3.org/TR/xquery/#dt-known-docs
  :)
declare function sctx:statically-known-document-type($document as xs:string) as xs:QName external;

(:~
 : The function returns a sequence that contains the statically known collations.
 :
 : @return The sequence of collations.
 :
 : @see http://www.w3.org/TR/xquery/#dt-static-collations
 :)
declare function sctx:statically-known-collations() as xs:anyURI* external;

(:~
 : The function returns the static context construction mode of element and
 : document nodes.
 :
 : @return Either "preserve" or "strip", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-construction-mode
 :)
declare function sctx:construction-mode() as xs:string external;

(:~
 : The function returns the static context ordering mode, which affects the
 : ordering of the result sequences returned by certain expressions.
 :
 : @return Either "ordered" or "unordered", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-ordering-mode
 :)
declare function sctx:ordering-mode() as xs:string external;

(:~
 : The function returns the static context component which controls the
 : processing of empty sequences and NaN values as ordering keys in an order
 : by clause in a FLWOR expression.
 :
 : @return Either "greatest" or "least", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-default-empty-order
 :)
declare function sctx:default-order() as xs:string external;

(:~
 : The function returns the static context component which contrls the
 : processing of boundary whitespace by direct element constructors.
 :
 : @return Either "preserve" or "strip", as strings.
 :
 : @see http://www.w3.org/TR/xquery/#dt-boundary-space-policy
 :)
declare function sctx:boundary-space-policy() as xs:string external;

(:~
 : The function returns the static context components which control the
 : the namespace bindings that are assigned when an existing element node
 : is copied by an element constructor
 :
 : @return A sequence containing exactly two strings, of which the first
 : has a value of either "preserve" or "no-preserve" and the second a value
 : of either "inherit" or "no-inherit".
 :
 : @see http://www.w3.org/TR/xquery/#dt-copy-namespaces-mode
 :)
declare function sctx:copy-namespaces-mode() as xs:string+ external;


Fixes for the JSon module.

Fixes for the JSon module.

(:
  : Copyright 2006-2009 The FLWOR Foundation.
  :
  : Licensed under the Apache License, Version 2.0 (the "License");
  : you may not use this file except in compliance with the License.
  : You may obtain a copy of the License at
  :
  : http://www.apache.org/licenses/LICENSE-2.0
  :
  : Unless required by applicable law or agreed to in writing, software
  : distributed under the License is distributed on an "AS IS" BASIS,
  : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  : See the License for the specific language governing permissions and
  : limitations under the License.
  :)

 (:~
  : In the XQuery specification, XQuery is described as a language capable of
  : expressing queries on XML data.

  : This makes XQuery the perfect choice for a data processing language on the
  : Web because XML is widely used there. However, there are also some other
  : data formats present on the Web.

  : For example, JSon
  : (JavaScript Object Notation) is the most common data format for applications
  : which are written in JavaScript.

  : Zorba implements a set of functions that opens XQuery developers the door to
  : processing other data formats (like JSon).

  : In this module, we describe these functions in detail.
  :
  : @author Sorin Nasoi
  : @version 1.0
  :
  :
1 JSon Functions

  :JSon is a lightweight hierarchical data-interchange format. Like XML, it is
  :easy for humans to read and write. Moreover, it is easy for machines to parse
  : and generate.

  :In order to process JSon with XQuery, Zorba implements a mapping between JSon
  : and XML that was proposed by John Snelson in his article
  : Parsing JSon into XQuery.

  : In this article, he describes the following recursive mapping declarations.

  :

  :

  :JSon 	type(JSon) 	toXML(JSon)

  :

  :JSon 	N/A 	<json type="type(JSon)">toXML(JSon)</json>

  :

  :{ "key1": value1, "key2": value2 } 	object 	<pair name="key1" type="type(value1)">toXML(value1)</pair><pair name="key2" type="type(value2)">toXML(value2)</pair>

  :

  :[ value1, value2 ] 	array 	<item type="type(value1)">toXML(value1)</item><item type="type(value2)">toXML(value2)</item>

  :

  :"value" 	string 	value

  :

  :number 	number 	number

  :

  :true / false 	boolean 	true / false

  :

  :null 	null 	empty

  :

  :

  :Zorba implements this mapping in two functions: the parse
  : function is used for parsing a sequence of JSon strings into a sequence of
  : elements, the serialize function implements the
  : reverse process, i.e. serializing a sequence of elements into a sequence of
  :valid JSon strings.

  :
  :
2 JSonML Functions

  :JSonML (JSon Markup Language)
  : is an application of the JSon
  : (JavaScript Object Notation) format.

  :The purpose of JSonML is to provide a compact format for transporting
  :XML-based markup as JSon. In contrast to the JSon mapping depicted above (see
  : 1 JSon Functions), JSonML allows a lossless
  : conversion back and forth.

  :Zorba implements the JSonML
  :structure defined in this article
  :Get to know JSonML

  :Analogoulsy to the JSon conversion, this functionality is implemented in a
  :parse-ml and serialize-ml
  :function, respectively.

  :Note:

  :Calling json:serialize-ml(json:parse-ml($some_string)) will not
  :always produce $some_string.

  :This is caused by the fact that json:serialize-ml does dot know the exact type
  : of the JSon value (true, false, null, numbers) and treats them all as strings.

  :Here are some possible cases where this can happen:

  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :  json:serialize-ml(json:parse-ml(('[ "ul",

  :                  [ "li", true],

  :                  [ "li", null],

  :                  [ "li", -14e12]

  :                  ]')))

  :

  :will output the following result:

  :

  :["ul",

  :  ["li", "true"],

  :  ["li"],

  :  ["li", "-1.4E+13"]

  :]

  :

  :
  :
3 Examples

  :
3.1 parse

  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :json:parse(('{

  :     "firstName": "John",

  :     "lastName": "Smith",

  :     "address": {

  :       "streetAddress": "21 2nd Street",

  :       "city": "New York",

  :       "state": "NY",

  :       "postalCode": 10021

  :     },

  :     "phoneNumbers": [

  :       "212 732-1234",

  :       "646 123-4567"

  :     ]

  : }',

  :'{

  :   "firstName": "John",

  :   "state": null,

  :   "bool": true ,

  :   "numbers": [1,2,3] ,

  :   "address": {

  :     "streetAddress": "21 2nd Street",

  :     "state": null,

  :     "postalCode": 10021 ,

  :     "literals": [true,false,null],

  :     "delivery": {

  :       "streetAddress": "StreetName",

  :       "city": "CityName",

  :       "state": "StateName",

  :     }

  :   } ,

  :   "strings": [

  :     "one",

  :     "two",

  :     "three",

  :     "four" ]

  :}'))

  :

  :
  :Executing this query and serializing its result to XML yields the following:
  :

  :  <json type="object">

  :    <pair name="firstName" type="string">John</pair>

  :    <pair name="lastName" type="string">Smith</pair>

  :    <pair name="address" type="object">

  :      <pair name="streetAddress" type="string">21 2nd Street</pair>

  :      <pair name="city" type="string">New York</pair>

  :      <pair name="state" type="string">NY</pair>

  :      <pair name="postalCode" type="number">10021</pair>

  :    </pair>

  :    <pair name="phoneNumbers" type="array">

  :      <item type="string">212 732-1234</item>

  :      <item type="string">646 123-4567</item>

  :    </pair>

  :  </json>

  :  <json type="object">

  :    <pair name="firstName" type="string">John</pair>

  :    <pair name="state" type="null"/>

  :    <pair name="bool" type="boolean">true</pair>

  :    <pair name="numbers" type="array">

  :      <item type="number">1</item>

  :      <item type="number">2</item>

  :      <item type="number">3</item>

  :    </pair>

  :    <pair name="address" type="object">

  :    <pair name="streetAddress" type="string">21 2nd Street</pair>

  :    <pair name="state" type="null"/>

  :    <pair name="postalCode" type="number">10021</pair>

  :    <pair name="literals" type="array">

  :      <item type="boolean">true</item>

  :      <item type="boolean">false</item>

  :      <item type="null"/>

  :    </pair>

  :    <pair name="delivery" type="object">

  :      <pair name="streetAddress" type="string">StreetName</pair>

  :      <pair name="city" type="string">CityName</pair>

  :      <pair name="state" type="string">StateName</pair>

  :    </pair>

  :  </pair>

  :  <pair name="strings" type="array">

  :    <item type="string">one</item>

  :    <item type="string">two</item>

  :    <item type="string">three</item>

  :    <item type="string">four</item>

  :  </pair>

  :</json>

  :

  :
  :
3.2 serialize

  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :declare variable $str as xs:string := '{"firstName": "John","state": null,"bool": true,"numbers": [1,2,3],"address": {"streetAddress": "21 2nd Street","state": null,"postalCode": 10021,"literals": [true,false,null],"delivery": {"streetAddress": "StreetName","city": "CityName","state": "StateName"}},"strings": ["one","two","three","four"]}';

  :
  :json:serialize(json:parse($str)) eq $str

  :

  :
  :
3.3 parse-ml

  :
  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :json:parse-ml(('[ "ul",

  :                [ "li",

  :                  true],

  :                [ "li",

  :                  {"href":"driving.html", "title":"Driving"},

  :                  "Second item"],

  :                [ "li", null],

  :                [ "li", -14]

  :                ]', '["table",{"class":"maintable"},

  :                      ["tr",{"class":"odd"},

  :                      ["th",{},"Situation"],

  :                      ["th","Result"]],

  :                      ["tr", {"class":"even"},

  :                      ["td",  ["a",  {"href":"driving.html", "title":"Driving"},"Driving"]],

  :                      ["td", "Busy"] ] ]'))

  :

  :Result :

  :

  :

  :
true

  :
Second item

  :

  :
-1.4E+13

  :

  :

  :

  :    Situation

  :    Result

  :

  :

  :    Driving

  :    Busy

  :

  :

  :

  :
  :
3.4 serialize-ml

  :
  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :json:serialize-ml((

true

Second item

-1.4

  :,

Situation	Result

Driving	Busy

))

  :

  :Result :

  :

  :  ["ul",

  :["li", "true"],

  :  ["li",{"href":"driving.html"}, {"title":"Driving"}, "Second item"],

  :  ["li"],

  :  ["li", "-1.4E+13"]

  :]

  :["table", {"class":"maintable"},

  :  ["tr", {"class":"odd"},

  :    ["th", "Situation"],

  :    ["th", "Result"]

  :  ],

  :  ["tr", {"class":"even"},

  :    ["td", ["a", {"href":"driving.html"}, {"title":"Driving"}, "Driving"]],

  :    ["td", "Busy"]

  :  ]

  :]

  :

  :
  :
  :)
module namespace json = "http://www.zorba-xquery.com/modules/json";

 (:~
  : Parsing JSon into the XQuery Data Model (XDM) according to the mapping in
  :John Snelson's article
  :
  : @param $text a sequence of valid JSon strings
  : @return  a sequence of nodes
  : @error API0060 if any of the strings passed as parameter are not a valid JSon
  :)
declare function json:parse(
  $text as xs:string*
) as node()* external;

(:~
 : The serialize function takes a sequence of nodes as parameter and
 : transforms each element into a valid JSon string according to the mapping
 : depicted in John Snelson's article.
 :
 : @param $xml a sequence of nodes conformant to the mapping described above
 : @return a sequence of JSon strings representation of the passed sequence of nodes
 : @error API0061 if the passed elements do not have a valid JSon structure
 : @error API0062 if the passed parameters are not nodes
 :)
declare function json:serialize(
  $xml as node()*
) as xs:string* external;

 (:~
  : Parsing JSon into the XQuery Data Model (XDM) according to the JSonML mapping
  :
  : @param $text a sequence of valid JSon string
  : @return a sequence of nodes
  : @error API0063 if the string representation of the value passed was empty or
  :any of the passed strings does not represend a valid JSon string
  :)
declare function json:parse-ml(
  $text as xs:string*
) as node()* external;

 (:~
  : The serialize function takes a sequence of elements as parameter and
  : transforms each element into a valid JSon string according to the JSonML
  :mapping
  : @param $xml valid JSon string according to JSonML mapping
  : @return a sequence of JSon strings representation of the passed sequence of nodes
  : @error API0064 if the passed elements do not have a valid JSon structure
  : @error API0065 if any of the passed parameters are not elements
  :)
declare function json:serialize-ml(
  $xml as node()*
) as xs:string* external;

(:
  : Copyright 2006-2009 The FLWOR Foundation.
  :
  : Licensed under the Apache License, Version 2.0 (the "License");
  : you may not use this file except in compliance with the License.
  : You may obtain a copy of the License at
  :
  : http://www.apache.org/licenses/LICENSE-2.0
  :
  : Unless required by applicable law or agreed to in writing, software
  : distributed under the License is distributed on an "AS IS" BASIS,
  : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  : See the License for the specific language governing permissions and
  : limitations under the License.
  :)

 (:~
  : In the XQuery specification, XQuery is described as a language capable of
  : expressing queries on XML data.

  : This makes XQuery the perfect choice for a data processing language on the
  : Web because XML is widely used there. However, there are also some other
  : data formats present on the Web.

  : For example, JSON
  : (JavaScript Object Notation) is the most common data format for applications
  : which are written in JavaScript.

  : Zorba implements a set of functions that opens XQuery developers the door to
  : processing other data formats (like JSon).

  : In this module, we describe these functions in detail.
  :
  : @author Sorin Nasoi
  : @version 1.0
  :
  :
1 JSON Functions

  :JSON is a lightweight hierarchical data-interchange format. Like XML, it is
  :easy for humans to read and write. Moreover, it is easy for machines to parse
  : and generate.

  :In order to process JSON with XQuery, Zorba implements a mapping between JSON
  : and XML that was proposed by John Snelson in his article
  : Parsing JSON into XQuery.

  : In this article, he describes the following recursive mapping declarations.

  :

  :

  :JSON 	type(JSON) 	toXML(JSON)

  :

  :JSON 	N/A 	<json type="type(JSON)">toXML(JSON)</json>

  :

  :{ "key1": value1, "key2": value2 } 	object 	<pair name="key1" type="type(value1)">toXML(value1)</pair><pair name="key2" type="type(value2)">toXML(value2)</pair>

  :

  :[ value1, value2 ] 	array 	<item type="type(value1)">toXML(value1)</item><item type="type(value2)">toXML(value2)</item>

  :

  :"value" 	string 	value

  :

  :number 	number 	number

  :

  :true / false 	boolean 	true / false

  :

  :null 	null 	empty

  :

  :

  :Zorba implements this mapping in two functions: the parse
  : function is used for parsing a sequence of JSON strings into a sequence of
  : elements, the serialize function implements the
  : reverse process, i.e. serializing a sequence of elements into a sequence of
  :valid JSON strings.

  :
  :
2 JSONML Functions

  :JsonML (JSON Markup Language)
  : is an application of the JSON
  : (JavaScript Object Notation) format.

  :The purpose of JsonML is to provide a compact format for transporting
  :XML-based markup as JSON. In contrast to the JSON mapping depicted above (see
  : 1 JSON Functions), JsonML allows a lossless
  : conversion back and forth.

  :Zorba implements the JsonML
  :structure defined in this article
  :Get to know JsonML

  :Analogoulsy to the JSON conversion, this functionality is implemented in a
  :parseML and serializeML
  :function, respectively.

  :Note:

  :Calling zorba-json-ml:serialize(zorba-json-ml:parse($some_string)) will not
  :always produce $some_string.

  :This is caused by the fact that jsonml:serialize does dot know the exact type
  : of the JSON value (true, false, null, numbers) and treats them all as strings.

  :Here are some possible cases where this can happen:

  :

  :import module namespace jsonml = "http://www.zorba-xquery.com/zorba/json-ml-functions";

  :
  :  jsonml:serialize(jsonml:parse(('[ "ul",

  :                  [ "li", true],

  :                  [ "li", null],

  :                  [ "li", -14e12]

  :                  ]')))

  :

  :will output the following result:

  :

  :["ul",

  :  ["li", "true"],

  :  ["li"],

  :  ["li", "-1.4E+13"]

  :]

  :

  :
  :
3 Examples

  :
3.1 parse

  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :json:parse(('{

  :     "firstName": "John",

  :     "lastName": "Smith",

  :     "address": {

  :       "streetAddress": "21 2nd Street",

  :       "city": "New York",

  :       "state": "NY",

  :       "postalCode": 10021

  :     },

  :     "phoneNumbers": [

  :       "212 732-1234",

  :       "646 123-4567"

  :     ]

  : }',

  :'{

  :   "firstName": "John",

  :   "state": null,

  :   "bool": true ,

  :   "numbers": [1,2,3] ,

  :   "address": {

  :     "streetAddress": "21 2nd Street",

  :     "state": null,

  :     "postalCode": 10021 ,

  :     "literals": [true,false,null],

  :     "delivery": {

  :       "streetAddress": "StreetName",

  :       "city": "CityName",

  :       "state": "StateName",

  :     }

  :   } ,

  :   "strings": [

  :     "one",

  :     "two",

  :     "three",

  :     "four" ]

  :}'))

  :

  :
  :Executing this query and serializing its result to XML yields the following:
  :

  :  <json type="object">

  :    <pair name="firstName" type="string">John</pair>

  :    <pair name="lastName" type="string">Smith</pair>

  :    <pair name="address" type="object">

  :      <pair name="streetAddress" type="string">21 2nd Street</pair>

  :      <pair name="city" type="string">New York</pair>

  :      <pair name="state" type="string">NY</pair>

  :      <pair name="postalCode" type="number">10021</pair>

  :    </pair>

  :    <pair name="phoneNumbers" type="array">

  :      <item type="string">212 732-1234</item>

  :      <item type="string">646 123-4567</item>

  :    </pair>

  :  </json>

  :  <json type="object">

  :    <pair name="firstName" type="string">John</pair>

  :    <pair name="state" type="null"/>

  :    <pair name="bool" type="boolean">true</pair>

  :    <pair name="numbers" type="array">

  :      <item type="number">1</item>

  :      <item type="number">2</item>

  :      <item type="number">3</item>

  :    </pair>

  :    <pair name="address" type="object">

  :    <pair name="streetAddress" type="string">21 2nd Street</pair>

  :    <pair name="state" type="null"/>

  :    <pair name="postalCode" type="number">10021</pair>

  :    <pair name="literals" type="array">

  :      <item type="boolean">true</item>

  :      <item type="boolean">false</item>

  :      <item type="null"/>

  :    </pair>

  :    <pair name="delivery" type="object">

  :      <pair name="streetAddress" type="string">StreetName</pair>

  :      <pair name="city" type="string">CityName</pair>

  :      <pair name="state" type="string">StateName</pair>

  :    </pair>

  :  </pair>

  :  <pair name="strings" type="array">

  :    <item type="string">one</item>

  :    <item type="string">two</item>

  :    <item type="string">three</item>

  :    <item type="string">four</item>

  :  </pair>

  :</json>

  :

  :
  :
3.2 serialize

  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :declare variable $str as xs:string := '{"firstName": "John","state": null,"bool": true,"numbers": [1,2,3],"address": {"streetAddress": "21 2nd Street","state": null,"postalCode": 10021,"literals": [true,false,null],"delivery": {"streetAddress": "StreetName","city": "CityName","state": "StateName"}},"strings": ["one","two","three","four"]}';

  :
  :json:serialize(json:parse($str)) eq $str

  :

  :
  :
3.3 parseML

  :
  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :json:parseML(('[ "ul",

  :                [ "li",

  :                  true],

  :                [ "li",

  :                  {"href":"driving.html", "title":"Driving"},

  :                  "Second item"],

  :                [ "li", null],

  :                [ "li", -14]

  :                ]', '["table",{"class":"maintable"},

  :                      ["tr",{"class":"odd"},

  :                      ["th",{},"Situation"],

  :                      ["th","Result"]],

  :                      ["tr", {"class":"even"},

  :                      ["td",  ["a",  {"href":"driving.html", "title":"Driving"},"Driving"]],

  :                      ["td", "Busy"] ] ]'))

  :

  :Result :

  :

  :

  :
true

  :
Second item

  :

  :
-1.4E+13

  :

  :

  :

  :    Situation

  :    Result

  :

  :

  :    Driving

  :    Busy

  :

  :

  :

  :
  :
3.4 serializeML

  :
  :

  :import module namespace json = "http://www.zorba-xquery.com/modules/json";

  :
  :json:serializeML((

true

Second item

-1.4

  :,

Situation	Result

Driving	Busy

))

  :

  :Result :

  :

  :  ["ul",

  :["li", "true"],

  :  ["li",{"href":"driving.html"}, {"title":"Driving"}, "Second item"],

  :  ["li"],

  :  ["li", "-1.4E+13"]

  :]

  :["table", {"class":"maintable"},

  :  ["tr", {"class":"odd"},

  :    ["th", "Situation"],

  :    ["th", "Result"]

  :  ],

  :  ["tr", {"class":"even"},

  :    ["td", ["a", {"href":"driving.html"}, {"title":"Driving"}, "Driving"]],

  :    ["td", "Busy"]

  :  ]

  :]

  :

  :
  :
Appendix A:  Error codes

  :  API0060 - API0060_CONV_JSON_PARSE - is raised if the string could not be parsed.

  :  API0061 - API0061_CONV_JSON_SERIALIZE - is raised if the element could not be serialized.

  :  API0062 - API0062_CONV_JSON_PARAM - is raised is the passed param is not an element.

  :  API0063 - API0063_CONV_JSON_ML_PARSE - is raised if the string could not be parsed.

  :  API0064 - API0064_CONV_JSON_ML_SERIALIZE - is raised if the element could not be serialized.

  :  API0065 - API0065_CONV_JSON_ML_PARAM - is raised is the passed parameter is not an element.

  :  API0066 - API0066_JSON_SEQUENCE_CANNOT_BE_SERIALIZED - Cannot serialize a sequence with more than one element if the 'json' or 'jsonml' method was selected.
  :)
module namespace json = "http://www.zorba-xquery.com/modules/json";

(:~
 : Parsing JSON into the XQuery Data Model (XDM)
 :
 : @param $text valid Json string according to John Snelson's article
 : @return true if the email was set successfully, false otherwise.
 : @error API0060 if any of the strings passed as parameter are not a valid JSON
 :)
declare function json:parse(
  $text as xs:string*
) as node()* external;

(:~
 : The serialize function takes a sequence of elements as parameter and
 : transforms each element into a valid JSON string according to the mapping
 : depicted above.
 :
 : @param $xml valid Json string according to John Snelson's article
 : @return the JSON representation of the passed $xml
 : @error API0061 if the passed elements do not have a valid JSON structure
 : @error API0062 if the passed parameter is not an element
 :)
declare function json:serialize(
  $xml as node()*
) as xs:string* external;

(:~
 : Parsing JSON into the XQuery Data Model (XDM)
 :
 : @param $text valid Json string according to John Snelson's article
 : @return true if the email was set successfully, false otherwise.
 : @error API0060 if any of the strings passed as parameter are not a valid JSON
 :)
declare function json:parse-ml(
  $text as xs:string*
) as node()* external;

(:~
 : The serialize function takes a sequence of elements as parameter and
 : transforms each element into a valid JSON string according to the mapping
 : depicted above.
 :
 : @param $xml valid Json string according to John Snelson's article
 : @return the JSON representation of the passed $xml
 : @error API0061 if the passed elements do not have a valid JSON structure
 : @error API0062 if the passed parameter is not an element
 :)
declare function json:serialize-ml(
  $xml as node()*
) as xs:string* external;


[testsuite] add tests for new range index condition features

xquery version "3.1";

(:~
 : Test conditions for complex range configuration elements.
 :
 :)
module namespace ct="http://exist-db.org/xquery/range/conditions/test";

import module namespace range="http://exist-db.org/xquery/range" at "java:org.exist.xquery.modules.range.RangeIndexModule";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace stats="http://exist-db.org/xquery/profiling";

declare variable $ct:COLLECTION_CONFIG :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:tei="http://www.tei-c.org/ns/1.0">
            <range>
                <create qname="tei:note">
                    <condition attribute="type" value="availability" />
                    <field name="availability" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note">
                    <condition attribute="type" value="text_type" />
                    <field name="text_type" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note">
                    <condition attribute="type" operator="starts-with" value="start" />
                    <field name="text_type_start" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note">
                    <condition attribute="type" operator="ends-with" value="end" />
                    <field name="text_type_end" type="xs:string" case="no"></field>
                </create>
                <create match="//tei:note">
                    <condition attribute="type" value="orig_place" />
                    <field name="orig_place" match="tei:place/tei:placeName" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note" type="xs:string" case="no" />
                <create qname="tei:placeName">
                    <condition attribute="type" value="someType" />
                    <condition attribute="cert" value="high" />
                    <field name="certainPlaceOfSomeType" type="xs:string" />
                </create>
                <create qname="tei:placeName">
                    <field name="allTypesOfPlaces" match="@type" type="xs:string" />
                </create>
                <create qname="tei:placeName">
                    <condition attribute="cert" value="low" />
                    <field name="typesOfUncertainPlaces" match="@type" type="xs:string" />
                </create>

                <create qname="tei:term">
                    <condition attribute="n" operator="lt" value="b" />
                    <field name="termsBeforeB" type="xs:string" />
                </create>
                <create qname="tei:term">
                    <condition attribute="n" operator="gt" value="b" />
                    <field name="termsAfterB" type="xs:string" />
                </create>
                <create qname="tei:term">
                    <condition attribute="n" operator="le" value="b" />
                    <field name="termsBeforeOrEqualB" type="xs:string" />
                </create>
                <create qname="tei:term">
                    <condition attribute="n" operator="ge" value="b" />
                    <field name="termsAfterOrEqualB" type="xs:string" />
                </create>
                <create qname="tei:term">
                    <condition attribute="n" operator="ne" value="b" />
                    <field name="termsNotB" type="xs:string" />
                </create>

                <create qname="tei:entry">
                    <condition attribute="n" operator="contains" value="1234" />
                    <field name="entryNContains1234" type="xs:string" />
                </create>
                <create qname="tei:entry">
                    <condition attribute="n" operator="matches" value="some_\d+_thing" />
                    <field name="entryNMatches" type="xs:string" />
                </create>

                <create qname="tei:num">
                    <condition attribute="value" operator="lt" value="2" />
                    <field name="lessThanTwoString" type="xs:string" />
                </create>
                <create qname="tei:num">
                    <condition attribute="value" operator="lt" value="2" numeric="yes"/>
                    <field name="lessThanTwoNumeric" type="xs:string" />
                </create>
                <create qname="tei:num">
                    <condition attribute="value" operator="eq" value="1" numeric="yes"/>
                    <field name="exactlyOne" type="xs:string" />
                </create>

                <create qname="tei:figure">
                    <condition attribute="n" operator="lt" value="2" numeric="yes"/>
                    <field name="figNLT2" type="xs:string" />
                </create>

                <create qname="tei:p">
                    <condition attribute="type" value="aabbcc" case="no" />
                    <field name="pCase" type="xs:string" />
                </create>
                <create qname="tei:p">
                    <condition attribute="type" operator="matches" value="bb" case="no" />
                    <field name="pMatchCase" type="xs:string" />
                </create>
            </range>
        </index>
    </collection>;

declare variable $ct:DATA :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0">
        <teiHeader>
            <fileDesc>
                <titleStmt><title>conditional fields!</title></titleStmt>
            </fileDesc>
            <sourceDesc>
                <msDesc>
                    <msContents>
                        <msItemStruct>
                            <note type="availability">publiziert</note>
                            <note type="text_type">literarisch</note>
                            <note type="orig_place">
                                <place>
                                    <placeName cert="low" type="thirdType">Oxyrhynchos</placeName>
                                </place>
                            </note>
                            <note>
                                <place>
                                    <placeName cert="high" type="someType" n="1">Achmim</placeName>
                                </place>
                                <place>
                                    <placeName cert="low" type="someType">Bubastos</placeName>
                                </place>
                                <place>
                                    <placeName cert="high" type="someOtherType">Alexandria</placeName>
                                </place>
                            </note>
                            <note type="start_end">startswithendswith</note>
                            <note>foo</note>
                            <note type="bar">foo</note>
                            <note type="something">literarisch</note>
                        </msItemStruct>
                    </msContents>
                </msDesc>
            </sourceDesc>
        </teiHeader>
        <text>

                    <term n="a">eins</term>
                    <term n="b">zwei</term>
                    <term n="c">drei</term>

                    <entry n="some_1234_thing">something</entry>

                    <num value="1">one</num>
                    <num value="110">onehundredandten</num>
                    <num value="2">two</num>
                    <num value="001.0">zerozeroonepointzero</num>

one

onehundredandten

two

CaseSensitivity

        </text>
    </TEI>;

declare variable $ct:COLLECTION_NAME := "optimizertest";
declare variable $ct:COLLECTION := "/db/" || $ct:COLLECTION_NAME;

declare
%test:setUp
function ct:setup() {
    xmldb:create-collection("/db/system/config/db", $ct:COLLECTION_NAME),
    xmldb:store("/db/system/config/db/" || $ct:COLLECTION_NAME, "collection.xconf", $ct:COLLECTION_CONFIG),
    xmldb:create-collection("/db", $ct:COLLECTION_NAME),
    xmldb:store($ct:COLLECTION, "data2.xml", $ct:DATA)

};

declare
%test:tearDown
function ct:cleanup() {
    xmldb:remove($ct:COLLECTION),
    xmldb:remove("/db/system/config/db/" || $ct:COLLECTION_NAME)
};

(: rewrite expression with predicate that matches a condition to a field  :)
(: the standard range lookup should not be used for the @type predicate :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq() {
    collection($ct:COLLECTION)//tei:note[@type="availability"][.="publiziert"]
};

(: rewrite expression with predicate that matches a condition to a field  :)
(: the standard range lookup should not be used for the @type predicate :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-numeric() {
    collection($ct:COLLECTION)//tei:num[@value = 1][.="publiziert"]
};

(: rewrite expression with predicate that matches a condition to a field  :)
(: the standard range lookup should not be used for the @type predicate :)
declare
%test:stats
%test:assertXPath("not($result//stats:index[@type = 'new-range'][@optimization = 2])")
function ct:no-optimize-eq-numeric() {
    collection($ct:COLLECTION)//tei:num[@value = "1"][.="publiziert"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-var() {
    let $var := "availability"
    return collection($ct:COLLECTION)//tei:note[@type=$var][.="publiziert"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-func() {
    collection($ct:COLLECTION)//tei:note[@type=lower-case("AVAILABILITY")][.="publiziert"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-reverse-var-nested() {
    let $var := "availability"
    let $var2 := $var
    return collection($ct:COLLECTION)//tei:note[$var2=@type][.="publiziert"]
};

declare variable $ct:var := "availability";
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-static-var() {
    collection($ct:COLLECTION)//tei:note[@type=$ct:var][.="publiziert"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq-reverse() {
    collection($ct:COLLECTION)//tei:note["availability" = @type][.="publiziert"]
};

(: rewrite expression with predicate that matches a condition to a field  :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-eq2() {
    collection($ct:COLLECTION)//tei:note[@type="orig_place"][tei:place/tei:placeName eq "Oxyrhynchos"]
};

declare
%test:assertEquals(1)
function ct:index-eq-no-case() {
count(range:index-keys-for-field("pCase", function($k, $n) { $k }, 10))
};

declare
%test:stats
%test:assertXPath("not($result//stats:index[@type = 'new-range'][@optimization = 2])")
function ct:optimize-case() {
collection($ct:COLLECTION)//tei:note[@type="Availablity"][.="publiziert"]
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'one') and contains($result, 'zerozeroonepointzero')")
function ct:index-eq-numeric() {
range:index-keys-for-field("exactlyOne", function($k, $n) { $k }, 10)
};

(: do not use a conditional field for optimizing if condition does not match :)
declare
%test:stats
%test:assertXPath("not($result//stats:index[@type = 'new-range'][@optimization = 2])")
function ct:no-optimize-condition2() {
collection($ct:COLLECTION)//tei:note[@type="something"][. = "literarisch"]
};

(: only the elements matching the condition should have been indexed :)
declare
%test:assertEquals(1)
function ct:conditional-config-results-eq() {
count(collection($ct:COLLECTION)//range:field-eq("text_type", "literarisch"))
};

(: if there are multiple config elements for a qname and some have a condition and :)
(: some have not, pick the one without condition if no condition matches :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ct:use-config-without-condition-optimize() {
collection($ct:COLLECTION)//tei:note[.="foo"]
};

declare
%test:assertEquals(2)
function ct:use-config-without-condition-result() {
count(collection($ct:COLLECTION)//tei:note[.="foo"])
};

(: rewrite expression with multiple conditions to the correct field :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2][@calls = 1] and not($result//stats:index[@type='range'])")
function ct:multiple-conditions() {
collection($ct:COLLECTION)//tei:placeName[@cert="high"][@type="someType"][.="Achmim"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2][@calls = 1] and $result//stats:index[@type='range'][@calls=1]")
function ct:multiple-conditions-inbetween() {
collection($ct:COLLECTION)//tei:placeName[@cert="high"][not(.="")][@type="someType"][.="Achmim"]
};

declare
%test:assertEquals("startswithendswith")
function ct:index-ends-with() {
range:index-keys-for-field("text_type_end", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-ends-with() {
collection($ct:COLLECTION)//tei:note[ends-with(@type, "end")][. = "startswithendswith"]
};

declare
%test:assertEquals("startswithendswith")
function ct:index-starts-with() {
range:index-keys-for-field("text_type_start", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-starts-with() {
collection($ct:COLLECTION)//tei:note[starts-with(@type, "start")][. = "startswithendswith"]
};

declare
%test:assertEquals("eins")
function ct:index-lt() {
range:index-keys-for-field("termsBeforeB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-lt() {
collection($ct:COLLECTION)//tei:term[@n < "b"][. = "eins"]
};

declare
%test:assertEquals("eins")
function ct:index-lt() {
range:index-keys-for-field("termsBeforeB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-lt() {
collection($ct:COLLECTION)//tei:term[@n < "b"][. = "eins"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-lt-numeric() {
collection($ct:COLLECTION)//tei:figure[@n < 2][. = "one"]
};

declare
%test:stats
%test:assertXPath("not($result//stats:index[@type = 'new-range'][@optimization = 2])")
function ct:no-optimize-lt-numeric() {
collection($ct:COLLECTION)//tei:figure[@n < "2"][. = "one"]
};

declare
%test:assertXPath("count($result) eq 3 and contains($result, 'one') and contains($result, 'onehundredandten') and contains($result, 'zerozeroonepointzero')")
function ct:index-lt-non-numeric() {
range:index-keys-for-field("lessThanTwoString", function($k, $n) { $k }, 10)
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'one') and contains($result, 'zerozeroonepointzero')")
function ct:index-lt-numeric() {
range:index-keys-for-field("lessThanTwoNumeric", function($k, $n) { $k }, 10)
};

declare
%test:assertEquals("drei")
function ct:index-gt() {
range:index-keys-for-field("termsAfterB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-gt() {
collection($ct:COLLECTION)//tei:term[@n > "b"][. = "drei"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-gt-inverse() {
collection($ct:COLLECTION)//tei:term["b" < @n][. = "eins"]
};

declare
%test:assertEquals("drei")
function ct:result-gt() {
collection($ct:COLLECTION)//tei:term[@n > "b"][. = "drei"]/text()
};

declare
%test:assertEquals("eins")
function ct:result-gt-inverse() {
collection($ct:COLLECTION)//tei:term["b" > @n][. = "eins"]/text()
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'eins') and contains($result, 'zwei')")
function ct:index-le() {
range:index-keys-for-field("termsBeforeOrEqualB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-le() {
collection($ct:COLLECTION)//tei:term[@n le "b"][. = "eins"]
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'zwei') and contains($result, 'drei')")
function ct:result-le-inverse() {
collection($ct:COLLECTION)//tei:term["b" le @n][true()]
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'zwei') and contains($result, 'drei')")
function ct:index-ge() {
range:index-keys-for-field("termsAfterOrEqualB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-ge() {
collection($ct:COLLECTION)//tei:term[@n ge "b"][. = "drei"]
};

declare
%test:assertXPath("count($result) eq 2 and contains($result, 'eins') and contains($result, 'drei')")
function ct:index-ne() {
range:index-keys-for-field("termsNotB", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-ne() {
collection($ct:COLLECTION)//tei:term[@n ne "b"][. = "drei"]
};

declare
%test:assertEquals("something")
function ct:index-contains() {
range:index-keys-for-field("entryNContains1234", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-contains() {
collection($ct:COLLECTION)//tei:entry[contains(@n, "1234")][. = "something"]
};

declare
%test:assertEquals("something")
function ct:index-matches() {
range:index-keys-for-field("entryNMatches", function($k, $n) { $k }, 10)
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-matches() {
collection($ct:COLLECTION)//tei:entry[matches(@n, "some_\d+_thing")][. = "something"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-matches-no-case() {
collection($ct:COLLECTION)//tei:p[matches(@type, "bb")][. = "something"]
};

xquery version "3.1";

(:~
 : Test conditions for complex range configuration elements.
 :
 :)
module namespace ct="http://exist-db.org/xquery/range/conditions/test";

import module namespace range="http://exist-db.org/xquery/range" at "java:org.exist.xquery.modules.range.RangeIndexModule";
import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare namespace tei="http://www.tei-c.org/ns/1.0";
declare namespace stats="http://exist-db.org/xquery/profiling";

declare variable $ct:COLLECTION_CONFIG :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:tei="http://www.tei-c.org/ns/1.0">
            <range>
                <create qname="tei:note">
                    <condition attribute="type" value="availability" />
                    <field name="availability" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note">
                    <condition attribute="type" value="text_type" />
                    <field name="text_type" type="xs:string" case="no"></field>
                </create>
                <create match="//tei:note">
                    <condition attribute="type" value="orig_place" />
                    <field name="orig_place" match="tei:place/tei:placeName" type="xs:string" case="no"></field>
                </create>
                <create qname="tei:note" type="xs:string" case="no" />
                <create qname="tei:placeName">
                    <condition attribute="type" value="someType" />
                    <condition attribute="cert" value="high" />
                    <field name="certainPlaceOfSomeType" type="xs:string" />
                </create>
                <create qname="tei:placeName">
                    <field name="allTypesOfPlaces" match="@type" type="xs:string" />
                </create>
                <create qname="tei:placeName">
                    <condition attribute="cert" value="low" />
                    <field name="typesOfUncertainPlaces" match="@type" type="xs:string" />
                </create>
            </range>
        </index>
    </collection>;

declare variable $ct:DATA :=
    <TEI xmlns="http://www.tei-c.org/ns/1.0">
        <teiHeader>
            <fileDesc>
                <titleStmt><title>conditional fields!</title></titleStmt>
            </fileDesc>
            <sourceDesc>
                <msDesc>
                    <msContents>
                        <msItemStruct>
                            <note type="availability">publiziert</note>
                            <note type="text_type">literarisch</note>
                            <note type="orig_place">
                                <place>
                                    <placeName cert="low" type="thirdType">Oxyrhynchos</placeName>
                                </place>
                            </note>
                            <note>
                                <place>
                                    <placeName cert="high" type="someType" n="1">Achmim</placeName>
                                </place>
                                <place>
                                    <placeName cert="low" type="someType">Bubastos</placeName>
                                </place>
                                <place>
                                    <placeName cert="high" type="someOtherType">Alexandria</placeName>
                                </place>
                            </note>
                            <note>foo</note>
                            <note type="bar">foo</note>
                            <note type="something">literarisch</note>
                        </msItemStruct>
                    </msContents>
                </msDesc>
            </sourceDesc>
        </teiHeader>
    </TEI>;

declare variable $ct:COLLECTION_NAME := "optimizertest";
declare variable $ct:COLLECTION := "/db/" || $ct:COLLECTION_NAME;

declare
%test:setUp
function ct:setup() {
    xmldb:create-collection("/db/system/config/db", $ct:COLLECTION_NAME),
    xmldb:store("/db/system/config/db/" || $ct:COLLECTION_NAME, "collection.xconf", $ct:COLLECTION_CONFIG),
    xmldb:create-collection("/db", $ct:COLLECTION_NAME),
    xmldb:store($ct:COLLECTION, "data2.xml", $ct:DATA)

};

declare
%test:tearDown
function ct:cleanup() {
    xmldb:remove($ct:COLLECTION),
    xmldb:remove("/db/system/config/db/" || $ct:COLLECTION_NAME)
};

(: rewrite expression with predicate that matches a condition to a field  :)
(: the standard range lookup should not be used for the @type predicate :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-with-condition() {
    collection($ct:COLLECTION)//tei:note[@type="availability"][.="publiziert"]
};

(: rewrite expression with predicate that matches a condition to a field  :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2] and not($result//stats:index[@type='range'])")
function ct:optimize-with-condition2() {
    collection($ct:COLLECTION)//tei:note[@type="orig_place"][tei:place/tei:placeName eq "Oxyrhynchos"]
};

(: do not use a conditional field for optimizing if condition does not match :)
declare
%test:stats
%test:assertXPath("not($result//stats:index[@type = 'new-range'][@optimization = 2])")
function ct:no-optimize-condition2() {
    collection($ct:COLLECTION)//tei:note[@type="something"][. = "literarisch"]
};

(: only the elements matching the condition should have been indexed :)
declare
%test:assertEquals(1)
function ct:conditional-config-restricts-results() {
count(collection($ct:COLLECTION)//range:field-eq("text_type", "literarisch"))
};

(: if there are multiple config elements for a qname and some have a condition and :)
(: some have not, pick the one without condition if no condition matches :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2]")
function ct:use-config-without-condition-optimize() {
collection($ct:COLLECTION)//tei:note[.="foo"]
};

declare
%test:assertEquals(2)
function ct:use-config-without-condition-result() {
count(collection($ct:COLLECTION)//tei:note[.="foo"])
};

(: rewrite expression with multiple conditions to the correct field :)
declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2][@calls = 1] and not($result//stats:index[@type='range'])")
function ct:multiple-conditions() {
collection($ct:COLLECTION)//tei:placeName[@cert="high"][@type="someType"][.="Achmim"]
};

declare
%test:stats
%test:assertXPath("$result//stats:index[@type = 'new-range'][@optimization = 2][@calls = 1] and $result//stats:index[@type='range'][@calls=1]")
function ct:multiple-conditions-inbetween() {
collection($ct:COLLECTION)//tei:placeName[@cert="high"][not(.="")][@type="someType"][.="Achmim"]
};


[bugfix] Be explicit about module hint

[bugfix] Be explicit about module hint

xquery version "3.1";

import module namespace t = "http://exist-db.org/xquery/testing"
    at "resource:org/exist/xquery/lib/test.xq";

declare variable $doc external;
declare variable $id as xs:string? external;

(: hooks for sending external notifications about test events :)
declare variable $test-ignored-function as (function(xs:string) as empty-sequence())? external;
declare variable $test-started-function as (function(xs:string) as empty-sequence())? external;
declare variable $test-failure-function as (function(xs:string, map(xs:string, item()?), map(xs:string, item()?)?) as empty-sequence())? external;
declare variable $test-assumption-failed-function as (function(xs:string, map(xs:string, item()?)) as empty-sequence())? external;
declare variable $test-error-function as (function(xs:string, map(xs:string, item()?)?) as empty-sequence())? external;
declare variable $test-finished-function as (function(xs:string) as empty-sequence())? external;

let $testSet :=
    if ($doc instance of xs:string) then
    	doc(concat("/db/test/", $doc))/TestSet
    else
    	$doc/TestSet
return
    t:run-testSet($testSet, $id,
            $test-ignored-function, $test-started-function, $test-failure-function,
            $test-assumption-failed-function, $test-error-function, $test-finished-function)

xquery version "3.1";

import module namespace t = "http://exist-db.org/xquery/testing";

declare variable $doc external;
declare variable $id as xs:string? external;

(: hooks for sending external notifications about test events :)
declare variable $test-ignored-function as (function(xs:string) as empty-sequence())? external;
declare variable $test-started-function as (function(xs:string) as empty-sequence())? external;
declare variable $test-failure-function as (function(xs:string, map(xs:string, item()?), map(xs:string, item()?)?) as empty-sequence())? external;
declare variable $test-assumption-failed-function as (function(xs:string, map(xs:string, item()?)) as empty-sequence())? external;
declare variable $test-error-function as (function(xs:string, map(xs:string, item()?)?) as empty-sequence())? external;
declare variable $test-finished-function as (function(xs:string) as empty-sequence())? external;

let $testSet :=
    if ($doc instance of xs:string) then
    	doc(concat("/db/test/", $doc))/TestSet
    else
    	$doc/TestSet
return
    t:run-testSet($testSet, $id,
            $test-ignored-function, $test-started-function, $test-failure-function,
            $test-assumption-failed-function, $test-error-function, $test-finished-function)