Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#21 #24

Merged
merged 10 commits into from
Jan 9, 2024
67 changes: 44 additions & 23 deletions context.xqm
Original file line number Diff line number Diff line change
Expand Up @@ -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(*)
{
Expand All @@ -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:)
Expand Down Expand Up @@ -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(*)
{
Expand All @@ -167,7 +178,8 @@ as map(*)
$instance,
$prolog || '$' || $var/@name,
$ns-elems,
$bindings
$bindings,
$options
)

(: let $_ := trace('[5]$bindings='||serialize($binding, map{'method':'adaptive'})) :)
Expand All @@ -177,7 +189,8 @@ as map(*)
$instance,
$namespaces,
$ns-elems,
$binding
$binding,
$options
)
};

Expand All @@ -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(*)
{
Expand All @@ -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'})) :)
Expand All @@ -225,7 +241,8 @@ as map(*)
$instance,
$namespaces,
$ns-elems,
$binding
$binding,
$options
)
};

Expand All @@ -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(
Expand Down Expand Up @@ -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,
Expand Down
150 changes: 125 additions & 25 deletions evaluate.xqm
Original file line number Diff line number Diff line change
Expand Up @@ -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
<svrl:schematron-output phase='#ALL'>
{output:schema-title($schema/sch:title)}
{$schema/@schemaVersion}
{output:namespace-decls-as-svrl($schema/sch:ns)}
<svrl:active-pattern name='XQS Syntax Error Summary' documents='{$schema/base-uri()}'/>
{$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)}
</svrl:schematron-output>
else
eval:schema($instance, $schema, $phase)
};

(:~ Evaluates the schema to produce SVRL output.
: @param instance the document instance
: @param schema the Schematron schema
Expand All @@ -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
<svrl:schematron-output>
Expand Down Expand Up @@ -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)
Expand All @@ -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:)(
<svrl:active-pattern>
{$pattern/(@id, @name, @role),
if($pattern/@documents) then attribute{'documents'}{$context?instance ! base-uri(.)} else()}
</svrl:active-pattern>,
$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 (
<svrl:active-pattern>
{$pattern/(@id, @name, @role),
if($pattern/@documents) then attribute{'documents'}{$context?instance ! base-uri(.)} else()}
</svrl:active-pattern>,
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
Expand Down Expand Up @@ -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(
<svrl:fired-rule>
{$rule/(@id, @name, @context, @role, @flag),
if($rule/../@documents) then attribute{'document'}{$context?instance/base-uri()} else ()}
</svrl:fired-rule>,
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
(
<svrl:fired-rule>
{$rule/(@id, @name, @context, @role, @flag),
if($rule/../@documents) then attribute{'document'}{$context?instance/base-uri()} else ()}
</svrl:fired-rule>,
eval:assertions($rule, $prolog, $rule-context, $context)
)
else ()
};

Expand Down Expand Up @@ -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 ()
Expand All @@ -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)))
};
Loading