diff --git a/context.xqm b/context.xqm
index 852aee1..dcd1f3c 100644
--- a/context.xqm
+++ b/context.xqm
@@ -19,11 +19,13 @@ declare variable $c:ALL_PATTERNS as xs:string := '#ALL';
: @param instance the document instance
: @param schema the Schematron schema
: @param phase the active phase
+ : @param options map of options
:)
declare function c:get-context(
$instance as node(),
$schema as element(sch:schema),
- $phase as xs:string?
+ $phase as xs:string?,
+ $options as map(*)?
)
as map(*)
{
@@ -39,20 +41,27 @@ as map(*)
$instance,
$namespaces,
$schema/sch:ns,
- map{}
+ map{},
+ $options
)
else map{}
- return map{
- 'phase' : $active-phase,
- 'patterns' : $active-patterns,
- 'ns-decls' : $namespaces,
- 'globals' : $globals,
- 'instance' : $instance,
- 'diagnostics' : $schema/sch:diagnostics/sch:diagnostic,
- 'properties' : $schema/sch:properties/sch:property,
- 'functions' : $schema/xqy:function
- }
+ return
+ map:merge(
+ (
+ $options,
+ map{
+ 'phase' : $active-phase,
+ 'patterns' : $active-patterns,
+ 'ns-decls' : $namespaces,
+ 'globals' : $globals,
+ 'instance' : $instance,
+ 'diagnostics' : $schema/sch:diagnostics/sch:diagnostic,
+ 'properties' : $schema/sch:properties/sch:property,
+ 'functions' : $schema/xqy:function
+ }
+ )
+ )
};
(:NAMESPACE DECLARATIONS:)
@@ -140,13 +149,15 @@ as element(sch:let)*
: @param instance the document instance
: @param namespaces namespace declarations
: @param bindings global variable bindings
+ : @param options map of options
:)
declare function c:evaluate-global-variables(
$variables as element(sch:let)*,
$instance as node(),
$namespaces as xs:string?,
$ns-elems as element(sch:ns)*,
- $bindings as map(*)
+ $bindings as map(*),
+ $options as map(*)?
)
as map(*)
{
@@ -167,7 +178,8 @@ as map(*)
$instance,
$prolog || '$' || $var/@name,
$ns-elems,
- $bindings
+ $bindings,
+ $options
)
(: let $_ := trace('[5]$bindings='||serialize($binding, map{'method':'adaptive'})) :)
@@ -177,7 +189,8 @@ as map(*)
$instance,
$namespaces,
$ns-elems,
- $binding
+ $binding,
+ $options
)
};
@@ -189,13 +202,15 @@ as map(*)
: @param variables pattern variables
: @param instance the document instance
: @param prolog global variable and namespace declarations
+ : @param options map of options
:)
declare function c:evaluate-root-context-variables(
$variables as element(sch:let)*,
$instance as node()+,
$namespaces as xs:string?,
$ns-elems as element(sch:ns)*,
- $bindings as map(*)
+ $bindings as map(*),
+ $options as map(*)?
)
as map(*)
{
@@ -215,7 +230,8 @@ as map(*)
$instance,
$prolog || utils:local-variable-decls($var) || ' return $' || $var/@name,
$ns-elems,
- $bindings
+ $bindings,
+ $options
)
(: let $_ := trace('[5]$bindings='||serialize($binding, map{'method':'adaptive'})) :)
@@ -225,7 +241,8 @@ as map(*)
$instance,
$namespaces,
$ns-elems,
- $binding
+ $binding,
+ $options
)
};
@@ -236,22 +253,25 @@ as map(*)
: @param query the query to evaluate
: @param ns-elems namespace declarations
: @param bindings map of global variable bindings
+ : @param options map of options
:)
declare function c:evaluate-global-variable(
$variable as element(sch:let),
$instance as node(),
$query as xs:string?,
$ns-elems as element(sch:ns)*,
- $bindings as map(*)
+ $bindings as map(*),
+ $options as map(*)?
)
as map(*)
{
(: let $_ := trace('>>>QUERY='||$query) :)
let $value as item()* := if($variable/@value)
- then xquery:eval(
+ then utils:eval(
$query => utils:escape(),
map:merge(($bindings, map{'':$instance})),
- map{'pass':'true'}
+ map:merge($options, map{'pass':'true'}),
+ $variable/@value
)
else $variable/*
let $bindings := map:merge(
@@ -283,10 +303,11 @@ as map(*)
{
if($documents)
then
- let $uris := xquery:eval(
+ let $uris := utils:eval(
utils:make-query-prolog($context) || $documents => utils:escape(),
map:merge(($context?globals, map{'':$context?instance})),
- map{'pass':'true'} (:report exception details:)
+ map{'pass':'true'}, (:report exception details:)
+ $documents
)
return map:put(
$context,
diff --git a/evaluate.xqm b/evaluate.xqm
index 0ade267..087bea7 100644
--- a/evaluate.xqm
+++ b/evaluate.xqm
@@ -11,9 +11,40 @@ import module namespace output = 'http://www.andrewsales.com/ns/xqs-output' at
import module namespace utils = 'http://www.andrewsales.com/ns/xqs-utils' at
'utils.xqm';
+declare namespace xqy = 'http://www.w3.org/2012/xquery';
declare namespace sch = "http://purl.oclc.org/dsdl/schematron";
declare namespace svrl = "http://purl.oclc.org/dsdl/svrl";
+(:~ Evaluates the schema to produce SVRL output, applying the processing options
+ : specified.
+ : @param instance the document instance
+ : @param schema the Schematron schema
+ : @param phase the active phase
+ : @param options map of processing options
+ :)
+declare function eval:schema(
+ $instance as node(),
+ $schema as element(sch:schema),
+ $phase as xs:string?,
+ $options as map(*)?
+)
+{
+ if($options?dry-run eq 'true')
+ then
+
+ {output:schema-title($schema/sch:title)}
+ {$schema/@schemaVersion}
+ {output:namespace-decls-as-svrl($schema/sch:ns)}
+
+ {$schema/xqy:function ! utils:parse-function(., $options)[self::svrl:*]}
+ {for $phase in ($schema/sch:phase/@id, '')
+ let $context as map(*) := context:get-context($instance, $schema, $phase, $options)
+ return eval:phase($context)}
+
+ else
+ eval:schema($instance, $schema, $phase)
+};
+
(:~ Evaluates the schema to produce SVRL output.
: @param instance the document instance
: @param schema the Schematron schema
@@ -25,7 +56,7 @@ declare function eval:schema(
$phase as xs:string?
)
{
- let $context as map(*) := context:get-context($instance, $schema, $phase)
+ let $context as map(*) := context:get-context($instance, $schema, $phase, map{})
return
@@ -57,7 +88,8 @@ declare function eval:pattern(
$context?instance,
$context?ns-decls,
$pattern/../sch:ns,
- $context?globals
+ $context?globals,
+ map{'dry-run':$context?dry-run}
)
(: let $_ := trace('PATTERN $globals='||serialize($globals, map{'method':'adaptive'})) :)
let $context := map:put($context, 'globals', $globals)
@@ -67,19 +99,59 @@ declare function eval:pattern(
(: let $_ := trace('PATTERN '||$pattern/@id||' prolog='||$prolog) :)
(: let $_ := trace('PATTERN $bindings '||serialize($context?globals, map{'method':'adaptive'})) :)
- return (:TODO active-pattern/@name:)(
-
- {$pattern/(@id, @name, @role),
- if($pattern/@documents) then attribute{'documents'}{$context?instance ! base-uri(.)} else()}
- ,
- $context?instance ! eval:rules(
- $pattern/sch:rule,
- utils:make-query-prolog($context),
- map:put($context, 'instance', .)
+ let $rules := $pattern/sch:rule
+ return (
+ if($context?dry-run eq 'true')
+ then
+ ($context?globals?*[self::svrl:*], eval:all-rules($rules, $context))
+ else (
+
+ {$pattern/(@id, @name, @role),
+ if($pattern/@documents) then attribute{'documents'}{$context?instance ! base-uri(.)} else()}
+ ,
+ eval:rules($rules, $context)
)
)
};
+(:~ Evaluates all the rules in a pattern.
+ : Initially added for use in dry-run mode, to check for syntax errors.
+ : N.B. we don't need to map the instance each time for this purpose, since we
+ : are not evaluating @documents, but this approach could be used for
+ : evaluating sch:rule-set (see https://github.com/AndrewSales/XQS/tree/%234).
+ :)
+declare function eval:all-rules(
+ $rules as element(sch:rule)*,
+ $context as map(*)
+)
+as element()*
+{
+ $context?instance
+ !
+ (for $rule in $rules
+ return
+ eval:rule(
+ $rule,
+ utils:make-query-prolog($context),
+ map:put($context, 'instance', .)
+ ))
+};
+
+declare function eval:rules(
+ $rules as element(sch:rule)*,
+ $context as map(*)
+)
+as element()*
+{
+ $context?instance
+ !
+ eval:rules(
+ $rules,
+ utils:make-query-prolog($context),
+ map:put($context, 'instance', .)
+ )
+};
+
(:~ Evaluate rules, stopping once one fires.
: (Necessitated by ISO2020 6.5.)
: @param rules the rules to evaluate
@@ -116,26 +188,43 @@ declare function eval:rule(
as element()*
{
let $_ := utils:check-duplicate-variable-names($rule/sch:let)
+ let $variable-errors := utils:evaluate-rule-variables(
+ $rule/sch:let,
+ $prolog,
+ map:merge((map{'':$context?instance}, $context?globals)),
+ $context,
+ ()
+ )
let $query := string-join(
($prolog, utils:local-variable-decls($rule/sch:let),
if($rule/sch:let) then 'return ' else '', $rule/@context),
' '
)
(: let $_ := trace('[2]RULE query='||$query) :)
- let $rule-context := xquery:eval(
+ let $rule-context := utils:eval(
$query => utils:escape(),
map:merge((map{'':$context?instance}, $context?globals)),
- map{'pass':'true'} (:report exception details:)
+ map{'dry-run':$context?dry-run},
+ $rule/@context
)
return
if($rule-context)
- then(
-
- {$rule/(@id, @name, @context, @role, @flag),
- if($rule/../@documents) then attribute{'document'}{$context?instance/base-uri()} else ()}
- ,
- eval:assertions($rule, $prolog, $rule-context, $context)
- )
+ then
+ if($context?dry-run eq 'true')
+ then
+ (
+ $variable-errors[self::svrl:*],
+ $rule-context[self::svrl:*],
+ eval:assertions($rule, $prolog, <_/>, $context) (:pass dummy context node:)
+ )
+ else
+ (
+
+ {$rule/(@id, @name, @context, @role, @flag),
+ if($rule/../@documents) then attribute{'document'}{$context?instance/base-uri()} else ()}
+ ,
+ eval:assertions($rule, $prolog, $rule-context, $context)
+ )
else ()
};
@@ -181,12 +270,20 @@ declare function eval:assertion(
$context as map(*)
)
{
- let $result := xquery:eval(
+ let $result := utils:eval(
$prolog || $assertion/@test => utils:escape(),
map:merge((map{'':$rule-context}, $context?globals)),
- map{'pass':'true'}
+ map{'dry-run':$context?dry-run},
+ $assertion/@test
)
return
+ if($context?dry-run eq 'true')
+ then
+ (
+ $result[self::svrl:*],
+ output:assertion-message($assertion, $prolog, $rule-context, $context)
+ )
+ else
typeswitch($assertion)
case element(sch:assert)
return if($result) then ()
@@ -206,15 +303,18 @@ declare function eval:phase($context as map(*))
let $phase := $context?phase
let $_ := utils:check-duplicate-variable-names($phase/sch:let)
+ let $dry-run as map(*) := map{'dry-run':$context?dry-run}
+
(:add phase variables to context:)
let $globals as map(*) := context:evaluate-root-context-variables(
$phase/sch:let,
$context?instance,
$context?ns-decls,
$phase/../sch:ns,
- $context?globals
+ $context?globals,
+ $dry-run
)
let $context := map:put($context, 'globals', $globals)
-
- return $context?patterns ! eval:pattern(., $context)
+
+ return $context?patterns ! eval:pattern(., map:merge(($context, $dry-run)))
};
\ No newline at end of file
diff --git a/svrl.xqm b/svrl.xqm
index ce08e2a..e80912c 100644
--- a/svrl.xqm
+++ b/svrl.xqm
@@ -3,6 +3,9 @@
:)
module namespace output = 'http://www.andrewsales.com/ns/xqs-output';
+import module namespace utils = 'http://www.andrewsales.com/ns/xqs-utils' at
+ 'utils.xqm';
+
declare namespace sch = "http://purl.oclc.org/dsdl/schematron";
declare namespace svrl = "http://purl.oclc.org/dsdl/svrl";
@@ -30,6 +33,14 @@ declare function output:assertion-message(
$context as map(*)
)
{
+ if($context?dry-run eq 'true')
+ then output:assertion-message-content(
+ $assertion/node(),
+ $prolog,
+ $rule-context,
+ $context
+ )
+ else
element{
QName("http://purl.oclc.org/dsdl/svrl",
if($assertion/self::sch:assert) then 'failed-assert' else 'successful-report')}
@@ -106,23 +117,34 @@ declare function output:assertion-message-content(
$rule-context as node(),
$context as map(*)
)
+as item()*
{
+ if($context?dry-run eq 'true')
+ then
+ for $node in $content/(self::sch:name|self::sch:value-of)
+ return
+ typeswitch($node)
+ case element(sch:name)
+ return if($node/@path)
+ then output:name-value-of($node/@path, $prolog, $rule-context, $context)
+ [self::svrl:*]
+ else ()
+ case element(sch:value-of)
+ return output:name-value-of($node/@select, $prolog, $rule-context, $context)
+ [self::svrl:*]
+ default return ()
+ else
{(:TODO attributes:)
for $node in $content
return
typeswitch($node)
case element(sch:name)
return if($node/@path)
- then xquery:eval(
- $prolog || $node/@path,
- map:merge((map{'':$rule-context}, $context?globals))
- )
+ then output:name-value-of($node/@path, $prolog, $rule-context, $context)
+ => string()
else name($rule-context)
case element(sch:value-of)
- return xquery:eval(
- $prolog || $node/@select,
- map:merge((map{'':$rule-context}, $context?globals))
- )
+ return output:name-value-of($node/@select, $prolog, $rule-context, $context)
=> string()
case element(sch:emph)
return output:assertion-child-elements($node)
@@ -132,4 +154,19 @@ declare function output:assertion-message-content(
return output:assertion-child-elements($node)
default return $node
}
+};
+
+declare function output:name-value-of(
+ $attr as attribute(),
+ $prolog as xs:string?,
+ $rule-context as node(),
+ $context as map(*)
+)
+{
+ utils:eval(
+ $prolog || $attr,
+ map:merge((map{'':$rule-context}, $context?globals)),
+ map{'dry-run':$context?dry-run},
+ $attr
+ )
};
\ No newline at end of file
diff --git a/test/global-variable-syntax-error.sch b/test/global-variable-syntax-error.sch
new file mode 100644
index 0000000..3a93ad9
--- /dev/null
+++ b/test/global-variable-syntax-error.sch
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/test-compile.xqm b/test/test-compile.xqm
index af513b5..bf5e8b4 100644
--- a/test/test-compile.xqm
+++ b/test/test-compile.xqm
@@ -1328,6 +1328,7 @@ declare %unit:test function _:global-variable-bindings()
document{},
'',
(),
+ map{},
map{}
)
return (
diff --git a/test/test-context.xqm b/test/test-context.xqm
index 3f204d4..5a5c094 100644
--- a/test/test-context.xqm
+++ b/test/test-context.xqm
@@ -271,7 +271,8 @@ declare %unit:test function _:get-context-patterns()
let $patterns := c:get-context(
,
$schema,
- 'phase1'
+ 'phase1',
+ map{}
)?patterns
return unit:assert-equals(
@@ -296,7 +297,8 @@ declare %unit:test function _:get-context-active-phase()
let $phase := c:get-context(
,
$schema,
- 'phase1'
+ 'phase1',
+ map{}
)?phase
return unit:assert-equals(
@@ -322,7 +324,8 @@ declare %unit:test function _:get-context-namespaces()
let $ns-decls := c:get-context(
,
$schema,
- ''
+ '',
+ map{}
)?ns-decls
return unit:assert-equals(
@@ -350,7 +353,8 @@ declare %unit:test function _:get-context-globals()
let $globals := c:get-context(
,
$schema,
- 'phase1'
+ 'phase1',
+ map{}
)?globals
return unit:assert-equals(
diff --git a/test/test-evaluate.xqm b/test/test-evaluate.xqm
index dc1b87e..12e20fb 100644
--- a/test/test-evaluate.xqm
+++ b/test/test-evaluate.xqm
@@ -6,6 +6,7 @@ module namespace _ = 'http://www.andrewsales.com/ns/xqs-evaluation-tests';
declare namespace sch = "http://purl.oclc.org/dsdl/schematron";
declare namespace svrl = "http://purl.oclc.org/dsdl/svrl";
+declare namespace xqy = 'http://www.w3.org/2012/xquery';
import module namespace eval = 'http://www.andrewsales.com/ns/xqs-evaluate'
at '../evaluate.xqm';
@@ -814,6 +815,7 @@ declare %unit:test function _:global-variable-bindings()
document{},
'',
(),
+ map{},
map{}
)
return (
@@ -1298,4 +1300,280 @@ declare %unit:test function _:map-rule-variable()
unit:assert(empty($result/svrl:failed-assert)),
unit:assert(empty($result/svrl:successful-report))
)
-};
\ No newline at end of file
+};
+
+declare %unit:test function _:global-variable-syntax-error()
+{
+ let $result := eval:schema(
+ document{},
+ doc('global-variable-syntax-error.sch')/*,
+ '',
+ map{'dry-run':'true'}
+ )
+ return (
+ unit:assert-equals(
+ $result/svrl:failed-assert/@location/data(),
+ "/Q{http://purl.oclc.org/dsdl/schematron}schema[1]/Q{http://purl.oclc.org/dsdl/schematron}let[1]/@value"
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert/@err:code/data(),
+ "err:XPST0003"
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert/svrl:text,
+ No specifier after lookup operator: ';'. @value='?'
+ )
+ )
+};
+
+declare %unit:test function _:pattern-variable-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ $result/svrl:failed-assert[ends-with(@location ,'/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}let[1]/@value')]
+ /svrl:text,
+ Incomplete FLWOR expression, expecting 'return'. @value='$'
+ )
+ )
+};
+
+declare %unit:test function _:rule-context-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ $result/svrl:failed-assert/svrl:text,
+ Expecting expression. @context=''
+ )
+ )
+};
+
+declare %unit:test function _:dry-run-all-rules-processed()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ count($result/svrl:fired-rule),
+ 2
+ )
+ )
+};
+
+declare %unit:test function _:rule-variable-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ count($result/svrl:failed-assert[ends-with(@location, '/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}rule[1]/Q{http://purl.oclc.org/dsdl/schematron}let[1]/@value')]),
+ 1
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert[ends-with(@location, '/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}rule[1]/Q{http://purl.oclc.org/dsdl/schematron}let[1]/@value')]/svrl:text,
+ Incomplete FLWOR expression, expecting 'return'. @value=''
+ )
+ )
+};
+
+declare %unit:test function _:report-test-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ count($result/svrl:failed-assert[ends-with(@location, '/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}rule[1]/Q{http://purl.oclc.org/dsdl/schematron}report[1]/@test')]),
+ 1
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert/svrl:text,
+ Namespace prefix not declared: ns. @test='ns:*'
+ )
+ )
+};
+
+declare %unit:test function _:name-path-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ count($result/svrl:failed-assert[ends-with(@location, '/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}rule[1]/Q{http://purl.oclc.org/dsdl/schematron}report[1]/Q{http://purl.oclc.org/dsdl/schematron}name[1]/@path')]),
+ 1
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert/svrl:text,
+ Unexpected end of query: '.'. @path='...'
+ )
+ )
+};
+
+declare %unit:test function _:value-of-select-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ count($result/svrl:failed-assert[ends-with(@location, '/Q{http://purl.oclc.org/dsdl/schematron}pattern[1]/Q{http://purl.oclc.org/dsdl/schematron}rule[1]/Q{http://purl.oclc.org/dsdl/schematron}report[1]/Q{http://purl.oclc.org/dsdl/schematron}value-of[1]/@select')]),
+ 1
+ ),
+ unit:assert-equals(
+ $result/svrl:failed-assert/svrl:text,
+ Unexpected end of query: '.'. @select='...'
+ )
+ )
+};
+
+declare %unit:test function _:phase-variable-scope-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ 'two',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ ($result/svrl:failed-assert)[1]/svrl:text,
+ Undeclared variable: $foo. @select='$foo'
+ )
+ )
+};
+
+(:TODO:)
+declare %unit:ignore function _:function-syntax-error()
+{
+ let $result :=
+ eval:schema(
+ document{},
+
+
+
+
+
+
+
+ ,
+ '',
+ map{'dry-run':'true'}
+ )
+ return
+ (
+ unit:assert-equals(
+ ($result/svrl:failed-assert)[1]/svrl:text,
+ Calculation is incomplete. xqy:function='declare function local:foo(){{**}};'
+ )
+ )
+};
+
+(:TODO
+pattern/@documents
+diagnostics
+properties
+functions
+:)
\ No newline at end of file
diff --git a/utils.xqm b/utils.xqm
index 907717b..c82aa7a 100644
--- a/utils.xqm
+++ b/utils.xqm
@@ -6,6 +6,7 @@ declare namespace xqs = 'http://www.andrewsales.com/ns/xqs';
declare namespace sch = "http://purl.oclc.org/dsdl/schematron";
declare namespace svrl = "http://purl.oclc.org/dsdl/svrl";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
+declare namespace xqy = 'http://www.w3.org/2012/xquery';
(:~ Builds the string of variable declarations in the prolog, for initial
: evaluation.
@@ -124,3 +125,85 @@ declare function utils:check-duplicate-variable-names($decls as element(sch:let)
|| $names[index-of($names, .)[2]]
) else()
};
+
+(:~ In dry-run mode only, evaluate rule variables.
+ : Provides more localized information if syntax errors are present in rule
+ : variable declarations.
+ :)
+declare function utils:evaluate-rule-variables(
+ $variables as element(sch:let)*,
+ $prolog as xs:string?,
+ $bindings as map(*),
+ $context as map(*),
+ $errors as element()*
+)
+as element()*
+{
+ if($context?dry-run eq 'true')
+ then
+ if(exists($variables))
+ then
+ let $var := head($variables)
+ let $prolog := $prolog || utils:local-variable-decls($var)
+ let $errs := utils:eval(
+ $prolog || ' return $' || $var/@name => utils:escape(),
+ $bindings,
+ map{'dry-run':$context?dry-run},
+ $var/@value
+ )
+ return utils:evaluate-rule-variables(
+ tail($variables),
+ $prolog,
+ $bindings,
+ $context,
+ ($errors,$errs)
+ )
+ else $errors
+ else ()
+};
+
+(:~ Wrapper around xquery:eval(). In "dry-run" mode, the query passed in is
+ : parsed only, and any errors caught reported as svrl:failed-assert.
+ : @param $query string of the query to evaluate
+ : @param bindings map of bindings
+ : @param options map of options
+ : @param node the schema node being evaluated
+ :)
+declare function utils:eval(
+ $query as xs:string,
+ $bindings as map(*),
+ $options as map(*),
+ $node as node()
+) as item()*
+{
+ if($options?dry-run eq 'true')
+ then
+ (,
+ try{
+ xquery:parse($query, map{'pass':'true'})
+ }
+ catch * {
+
+ {$err:description}{' @'||$node/name()}='{$node/data()}'
+ })
+ else xquery:eval($query, $bindings, map{'pass':'true'})
+};
+
+declare function utils:parse-function(
+ $node as element(xqy:function),
+ $options as map(*)
+)
+as element()+
+{
+ ,
+ try{
+ xquery:parse($node || 0, map{'pass':'true'})
+ }
+ catch * {
+
+ {$err:description}{' '||$node/name()}='{$node/data()}'
+
+ }
+};
\ No newline at end of file