Skip to content

Commit 74dca1a

Browse files
MariusSameeraPriyathamTadikonda
authored andcommitted
DEVEXP-280: validateDoc implementation in node-client-api
1 parent 3306198 commit 74dca1a

File tree

6 files changed

+605
-1
lines changed

6 files changed

+605
-1
lines changed

etc/data/validateDoc-test.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"language": "zxx",
3+
"$schema": "http://json-schema.org/draft-07/schema#",
4+
"properties": {
5+
"count": { "type":"integer", "minimum":0 },
6+
"items": { "type":"array", "items": {"type":"string", "minLength":1 } }
7+
}
8+
}

etc/data/validateDoc-test.sch

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<sch:schema xmlns:sch="http://purl.oclc.org/dsdl/schematron"
2+
queryBinding="xslt2" schemaVersion="1.0">
3+
<sch:title>user-validation</sch:title>
4+
<sch:phase id="phase1">
5+
<sch:active pattern="structural"></sch:active>
6+
</sch:phase>
7+
<sch:phase id="phase2">
8+
<sch:active pattern="co-occurence"></sch:active>
9+
</sch:phase>
10+
<sch:pattern id="structural">
11+
<sch:rule context="user">
12+
<sch:assert test="@id">user element must have an id attribute</sch:assert>
13+
<sch:assert test="count(*) = 5">
14+
user element must have 5 child elements: name, gender,
15+
age, score and result
16+
</sch:assert>
17+
<sch:assert test="score/@total">score element must have a total attribute</sch:assert>
18+
<sch:assert test="score/count(*) = 2">score element must have two child elements</sch:assert>
19+
</sch:rule>
20+
</sch:pattern>
21+
<sch:pattern id="co-occurence">
22+
<sch:rule context="score">
23+
<sch:assert test="@total = test-1 + test-2">
24+
total score must be a sum of test-1 and test-2 scores
25+
</sch:assert>
26+
<sch:assert test="(@total gt 30 and ../result = 'pass') or
27+
(@total le 30 and ../result = 'fail')" diagnostics="d1">
28+
if the score is greater than 30 then the result will be
29+
'pass' else 'fail'
30+
</sch:assert>
31+
</sch:rule>
32+
</sch:pattern>
33+
<sch:diagnostics>
34+
<sch:diagnostic id="d1">the score does not match with the result</sch:diagnostic>
35+
</sch:diagnostics>
36+
</sch:schema>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xsl:stylesheet extension-element-prefixes="xdmp" xdmp:dialect="1.0-ml" version="2.0" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xdmp="http://marklogic.com/xdmp" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3+
<!--Implementers: please note that overriding process-prolog or process-root is
4+
the preferred method for meta-stylesheets to use where possible. -->
5+
<xsl:param name="archiveDirParameter"/>
6+
<xsl:param name="archiveNameParameter"/>
7+
<xsl:param name="fileNameParameter"/>
8+
<xsl:param name="fileDirParameter"/>
9+
<xsl:variable name="document-uri"><xsl:value-of select="document-uri(/)"/></xsl:variable>
10+
<!--PHASES-->
11+
<!--PROLOG-->
12+
<xsl:output method="xml" omit-xml-declaration="no" standalone="yes" indent="yes" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"/>
13+
<!--XSD TYPES FOR XSLT2-->
14+
<!--KEYS AND FUNCTIONS-->
15+
<!--DEFAULT RULES-->
16+
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
17+
<!--This mode can be used to generate an ugly though full XPath for locators-->
18+
<xsl:template match="*|/|object-node()" mode="schematron-select-full-path"><xsl:apply-templates select="." mode="schematron-get-full-path"/></xsl:template>
19+
<!--MODE: SCHEMATRON-FULL-PATH-->
20+
<!--This mode can be used to generate an ugly though full XPath for locators-->
21+
<xsl:template match="*|/|object-node()" mode="schematron-get-full-path"><xsl:value-of select="xdmp:path(.)"/></xsl:template>
22+
<xsl:template match="@*" mode="schematron-get-full-path"><xsl:value-of select="xdmp:path(.)"/></xsl:template>
23+
<!--MODE: SCHEMATRON-FULL-PATH-2-->
24+
<!--This mode can be used to generate prefixed XPath for humans-->
25+
<xsl:template match="node() | @*" mode="schematron-get-full-path-2"><xsl:for-each select="ancestor-or-self::*"><xsl:text>/</xsl:text><xsl:value-of select="name(.)"/><xsl:if test="preceding-sibling::*[name(.)=name(current())]"><xsl:text>[</xsl:text><xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/><xsl:text>]</xsl:text></xsl:if></xsl:for-each><xsl:if test="not(self::*)"><xsl:text/>/@<xsl:value-of select="name(.)"/></xsl:if></xsl:template>
26+
<!--MODE: SCHEMATRON-FULL-PATH-3-->
27+
<!--This mode can be used to generate prefixed XPath for humans
28+
(Top-level element has index)-->
29+
<xsl:template match="node() | @*" mode="schematron-get-full-path-3"><xsl:for-each select="ancestor-or-self::*"><xsl:text>/</xsl:text><xsl:value-of select="name(.)"/><xsl:if test="parent::*"><xsl:text>[</xsl:text><xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/><xsl:text>]</xsl:text></xsl:if></xsl:for-each><xsl:if test="not(self::*)"><xsl:text/>/@<xsl:value-of select="name(.)"/></xsl:if></xsl:template>
30+
<!--MODE: GENERATE-ID-FROM-PATH -->
31+
<xsl:template match="/" mode="generate-id-from-path"/>
32+
<xsl:template match="text()" mode="generate-id-from-path"><xsl:apply-templates select="parent::*" mode="generate-id-from-path"/><xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')"/></xsl:template>
33+
<xsl:template match="comment()" mode="generate-id-from-path"><xsl:apply-templates select="parent::*" mode="generate-id-from-path"/><xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')"/></xsl:template>
34+
<xsl:template match="processing-instruction()" mode="generate-id-from-path"><xsl:apply-templates select="parent::*" mode="generate-id-from-path"/><xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')"/></xsl:template>
35+
<xsl:template match="@*" mode="generate-id-from-path"><xsl:apply-templates select="parent::*" mode="generate-id-from-path"/><xsl:value-of select="concat('.@', name())"/></xsl:template>
36+
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5"><xsl:apply-templates select="parent::*" mode="generate-id-from-path"/><xsl:text>.</xsl:text><xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')"/></xsl:template>
37+
<!--MODE: GENERATE-ID-2 -->
38+
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
39+
<xsl:template match="*" mode="generate-id-2" priority="2"><xsl:text>U</xsl:text><xsl:number level="multiple" count="*"/></xsl:template>
40+
<xsl:template match="node()" mode="generate-id-2"><xsl:text>U.</xsl:text><xsl:number level="multiple" count="*"/><xsl:text>n</xsl:text><xsl:number count="node()"/></xsl:template>
41+
<xsl:template match="@*" mode="generate-id-2"><xsl:text>U.</xsl:text><xsl:number level="multiple" count="*"/><xsl:text>_</xsl:text><xsl:value-of select="string-length(local-name(.))"/><xsl:text>_</xsl:text><xsl:value-of select="translate(name(),':','.')"/></xsl:template>
42+
<!--Strip characters-->
43+
<xsl:template match="text()|number-node()|boolean-node()|null-node()" priority="-1"/>
44+
<!--SCHEMA SETUP-->
45+
<xsl:template match="/"><svrl:schematron-output title="user-validation" schemaVersion="1.0" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:comment><xsl:value-of select="$archiveDirParameter"/>
46+
<xsl:value-of select="$archiveNameParameter"/>
47+
<xsl:value-of select="$fileNameParameter"/>
48+
<xsl:value-of select="$fileDirParameter"/></xsl:comment><svrl:active-pattern><xsl:attribute name="document"><xsl:value-of select="document-uri(/)"/></xsl:attribute><xsl:attribute name="id">structural</xsl:attribute><xsl:attribute name="name">structural</xsl:attribute><xsl:apply-templates/></svrl:active-pattern><xsl:apply-templates select="/" mode="M3"/><svrl:active-pattern><xsl:attribute name="document"><xsl:value-of select="document-uri(/)"/></xsl:attribute><xsl:attribute name="id">co-occurence</xsl:attribute><xsl:attribute name="name">co-occurence</xsl:attribute><xsl:apply-templates/></svrl:active-pattern><xsl:apply-templates select="/" mode="M4"/></svrl:schematron-output></xsl:template>
49+
<!--SCHEMATRON PATTERNS-->
50+
<svrl:text xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl">user-validation</svrl:text>
51+
<!--PATTERN structural-->
52+
<!--RULE -->
53+
<xsl:template match="user" priority="1000" mode="M3"><svrl:fired-rule context="user" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"/>
54+
55+
<!--ASSERT -->
56+
<xsl:choose>
57+
<xsl:when test="@id"/>
58+
<xsl:otherwise><svrl:failed-assert test="@id" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>user element must have an id attribute</svrl:text></svrl:failed-assert></xsl:otherwise>
59+
</xsl:choose>
60+
61+
<!--ASSERT -->
62+
<xsl:choose>
63+
<xsl:when test="count(*) = 5"/>
64+
<xsl:otherwise><svrl:failed-assert test="count(*) = 5" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>
65+
user element must have 5 child elements: name, gender,
66+
age, score and result
67+
</svrl:text></svrl:failed-assert></xsl:otherwise>
68+
</xsl:choose>
69+
70+
<!--ASSERT -->
71+
<xsl:choose>
72+
<xsl:when test="score/@total"/>
73+
<xsl:otherwise><svrl:failed-assert test="score/@total" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>score element must have a total attribute</svrl:text></svrl:failed-assert></xsl:otherwise>
74+
</xsl:choose>
75+
76+
<!--ASSERT -->
77+
<xsl:choose>
78+
<xsl:when test="score/count(*) = 2"/>
79+
<xsl:otherwise><svrl:failed-assert test="score/count(*) = 2" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>score element must have two child elements</svrl:text></svrl:failed-assert></xsl:otherwise>
80+
</xsl:choose><xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3"/></xsl:template>
81+
<xsl:template match="text()" priority="-1" mode="M3"/>
82+
<xsl:template match="@*|node()" priority="-2" mode="M3"><xsl:apply-templates select="*|comment()|processing-instruction()" mode="M3"/></xsl:template>
83+
<!--PATTERN co-occurence-->
84+
<!--RULE -->
85+
<xsl:template match="score" priority="1000" mode="M4"><svrl:fired-rule context="score" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"/>
86+
87+
<!--ASSERT -->
88+
<xsl:choose>
89+
<xsl:when test="@total = test-1 + test-2"/>
90+
<xsl:otherwise><svrl:failed-assert test="@total = test-1 + test-2" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>
91+
total score must be a sum of test-1 and test-2 scores
92+
</svrl:text></svrl:failed-assert></xsl:otherwise>
93+
</xsl:choose>
94+
95+
<!--ASSERT -->
96+
<xsl:choose>
97+
<xsl:when test="(@total gt 30 and ../result = 'pass') or (@total le 30 and ../result = 'fail')"/>
98+
<xsl:otherwise><svrl:failed-assert test="(@total gt 30 and ../result = 'pass') or (@total le 30 and ../result = 'fail')" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" xmlns:svrl="http://purl.oclc.org/dsdl/svrl"><xsl:attribute name="location"><xsl:apply-templates select="." mode="schematron-select-full-path"/></xsl:attribute><svrl:text>
99+
if the score is greater than 30 then the result will be
100+
'pass' else 'fail'
101+
</svrl:text> <svrl:diagnostic-reference diagnostic="d1">
102+
the score does not match with the result</svrl:diagnostic-reference></svrl:failed-assert></xsl:otherwise>
103+
</xsl:choose><xsl:apply-templates select="*|comment()|processing-instruction()" mode="M4"/></xsl:template>
104+
<xsl:template match="text()" priority="-1" mode="M4"/>
105+
<xsl:template match="@*|node()" priority="-2" mode="M4"><xsl:apply-templates select="*|comment()|processing-instruction()" mode="M4"/></xsl:template>
106+
</xsl:stylesheet>

etc/test-setup.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,37 @@ const moduleFiles = [
8989
{'role-name':testconfig.restAdminConnection.user, capabilities:['read', 'execute', 'update']}
9090
],
9191
content:fs.createReadStream('./etc/data/articleCitation.json')
92+
},{ uri:'/validateDoc-test.json',
93+
contentType:'application/json',
94+
collections:['http://marklogic.com/xdmp/tde'],
95+
permissions: [
96+
{'role-name':'app-user', capabilities:['read', 'execute']},
97+
{'role-name':'app-builder', capabilities:['read', 'execute']},
98+
{'role-name':testconfig.restReaderConnection.user, capabilities:['read', 'execute', 'update']},
99+
{'role-name':testconfig.restWriterConnection.user, capabilities:['read', 'execute', 'update']},
100+
{'role-name':testconfig.restAdminConnection.user, capabilities:['read', 'execute', 'update']}
101+
],
102+
content:fs.createReadStream('./etc/data/validateDoc-test.json')
103+
}, { uri:'/validateDoc-test.sch',
104+
contentType:'application/vnd.marklogic-tde+xml',
105+
permissions: [
106+
{'role-name':'app-user', capabilities:['read', 'execute']},
107+
{'role-name':'app-builder', capabilities:['read', 'execute']},
108+
{'role-name':testconfig.restReaderConnection.user, capabilities:['read', 'execute', 'update']},
109+
{'role-name':testconfig.restWriterConnection.user, capabilities:['read', 'execute', 'update']},
110+
{'role-name':testconfig.restAdminConnection.user, capabilities:['read', 'execute', 'update']}
111+
],
112+
content:fs.createReadStream('./etc/data/validateDoc-test.sch')
113+
},{ uri:'/validateDoc-test.sch-validator.xsl',
114+
contentType:'application/vnd.marklogic-tde+xml',
115+
permissions: [
116+
{'role-name':'app-user', capabilities:['read', 'execute']},
117+
{'role-name':'app-builder', capabilities:['read', 'execute']},
118+
{'role-name':testconfig.restReaderConnection.user, capabilities:['read', 'execute', 'update']},
119+
{'role-name':testconfig.restWriterConnection.user, capabilities:['read', 'execute', 'update']},
120+
{'role-name':testconfig.restAdminConnection.user, capabilities:['read', 'execute', 'update']}
121+
],
122+
content:fs.createReadStream('./etc/data/validateDoc-test.sch-validator.xsl')
92123
}, {
93124
uri:'/optic/test/transformDoc-test.mjs',
94125
contentType:'application/vnd.marklogic-javascript',
@@ -595,7 +626,7 @@ function setup(manager) {
595626
});
596627
} else {
597628
console.log(testconfig.testServerName+' test server is available on port '+
598-
response.data.port);
629+
JSON.parse(response.data).port);
599630
}
600631
});
601632
}

lib/plan-builder-base.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,38 @@ function castArg(arg, funcName, paramName, argPos, paramTypes) {
315315
return true;
316316
}
317317
});
318+
case 'PlanSchemaDef':
319+
const objKeysPlanSchemaDef = Object.keys(arg);
320+
if(!objKeysPlanSchemaDef.includes('kind')) {
321+
return false;
322+
}
323+
return objKeysPlanSchemaDef.every(key => {
324+
if(key === 'kind') {
325+
if(typeof arg[key] !== "string") {
326+
throw new Error(
327+
`${argLabel(funcName, paramName, argPos)} has another type than string`
328+
);
329+
} else {
330+
return true;
331+
}
332+
}
333+
if(key === 'mode') {
334+
if(typeof arg[key] !== "string") {
335+
throw new Error(
336+
`${argLabel(funcName, paramName, argPos)} has another type than string`
337+
);
338+
}
339+
return true;
340+
}
341+
if(key === 'schemaUri') {
342+
if(typeof arg[key] !== "string") {
343+
throw new Error(
344+
`${argLabel(funcName, paramName, argPos)} has another type than string`
345+
);
346+
}
347+
return true;
348+
}
349+
});
318350
case 'PlanTransformDef':
319351
return Object.keys(arg).every(key => {
320352
const value = arg[key];

0 commit comments

Comments
 (0)