diff --git a/INSTALL.md b/INSTALL.md
index 062de202..d1a1ef4a 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -104,52 +104,42 @@ Additional Makefile parameters
The following parameters can be given to `make` to control certain
options when building and installing.
-### `BREXCHECK_XPATH_ENGINE`
+### `PREFIX`
+
+The `PREFIX` variable determines where the s1kd-tools are installed when
+running `make install`, and where they are uninstalled from when running
+`make uninstall`. The default value is `/usr/local`.
+
+Example:
-The `BREXCHECK_XPATH_ENGINE` variable determines which XPath
-implementation the s1kd-brexcheck tool will use to evaluate the object
-paths of BREX rules.
+ # make PREFIX=/usr install
+
+ # make PREFIX=/usr uninstall
+
+### `XPATH2_ENGINE`
+
+The `XPATH2_ENGINE` variable determines which XPath 2.0 implementation
+the s1kd-brexcheck tool will use to evaluate the object paths of BREX
+rules.
The s1kd-tools are built on libxml, so by default s1kd-brexcheck uses
libxml's XPath implementation. However, libxml only supports XPath 1.0.
While as of Issue 5.0, the S1000D default BREX rules are all compatible
with XPath 1.0, Issue 4.0 and up do reference the XPath 2.0
specification. Therefore, if your project needs XPath 2.0 support for
-BREX rules, you should select a different implementation.
-
-`LIBXML`
-The default implementation. Fast and requires no additional
-dependencies.
-
-Supports XPath 1.0 and some EXSLT functions.
+BREX rules, you should select one of these implementations:
`SAXON`
Experimental implementation using the Saxon/C library. Slower, and
Saxon/C itself is a very large dependency. Not recommended at this time
due to memory leak issues.
-Supports XPath 1.0, 2.0 and 3.0.
-
`XQILLA`
Experimental implementation using the Xerces-C and XQilla libraries. A
little slower than libxml, but faster than Saxon/C, and the dependencies
are much smaller than the latter. This is currently the recommended
implementation if you need XPath 2.0 support.
-Supports XPath 1.0 and 2.0.
-
-Example:
-
- $ make BREXCHECK_XPATH_ENGINE=XQILLA
-
-### `PREFIX`
-
-The `PREFIX` variable determines where the s1kd-tools are installed when
-running `make install`, and where they are uninstalled from when running
-`make uninstall`. The default value is `/usr/local`.
-
Example:
- # make PREFIX=/usr install
-
- # make PREFIX=/usr uninstall
+ $ make XPATH2_ENGINE=XQILLA
diff --git a/doc/DMC-S1KDTOOLS-A-00-00-00-00A-920A-D_EN-CA.XML b/doc/DMC-S1KDTOOLS-A-00-00-00-00A-920A-D_EN-CA.XML
index 7f7dbaba..399f8678 100644
--- a/doc/DMC-S1KDTOOLS-A-00-00-00-00A-920A-D_EN-CA.XML
+++ b/doc/DMC-S1KDTOOLS-A-00-00-00-00A-920A-D_EN-CA.XML
@@ -198,28 +198,29 @@
The following parameters can be given to make to control certain options when building and installing.
- BREXCHECK_XPATH_ENGINE
+ PREFIX
+
+ The PREFIX variable determines where the s1kd-tools are installed when running make install , and where they are uninstalled from when running make uninstall . The default value is /usr/local .
+
+ Example:
+ # make PREFIX=/usr install
+ # make PREFIX=/usr uninstall
+
+
+
+
+ XPATH2_ENGINE
- The BREXCHECK_XPATH_ENGINE variable determines which XPath implementation the s1kd-brexcheck tool will use to evaluate the object paths of BREX rules.
- The s1kd-tools are built on libxml, so by default s1kd-brexcheck uses libxml's XPath implementation. However, libxml only supports XPath 1.0. While as of Issue 5.0, the S1000D default BREX rules are all compatible with XPath 1.0, Issue 4.0 and up do reference the XPath 2.0 specification. Therefore, if your project needs XPath 2.0 support for BREX rules, you should select a different implementation.
+ The XPATH2_ENGINE variable determines which XPath 2.0 implementation the s1kd-brexcheck tool will use to evaluate the object paths of BREX rules.
+ The s1kd-tools are built on libxml, so by default s1kd-brexcheck uses libxml's XPath implementation. However, libxml only supports XPath 1.0. While as of Issue 5.0, the S1000D default BREX rules are all compatible with XPath 1.0, Issue 4.0 and up do reference the XPath 2.0 specification. Therefore, if your project needs XPath 2.0 support for BREX rules, you should select one of these implementations:
-
-
- LIBXML
-
-
- The default implementation. Fast and requires no additional dependencies.
- Supports XPath 1.0 and some EXSLT functions.
-
-
SAXON
Experimental implementation using the Saxon/C library. Slower, and Saxon/C itself is a very large dependency. Not recommended at this time due to memory leak issues.
- Supports XPath 1.0, 2.0 and 3.0.
@@ -228,25 +229,13 @@
Experimental implementation using the Xerces-C and XQilla libraries. A little slower than libxml, but faster than Saxon/C, and the dependencies are much smaller than the latter. This is currently the recommended implementation if you need XPath 2.0 support.
- Supports XPath 1.0 and 2.0.
Example:
- $ make BREXCHECK_XPATH_ENGINE=XQILLA
-
-
-
-
- PREFIX
-
- The PREFIX variable determines where the s1kd-tools are installed when running make install , and where they are uninstalled from when running make uninstall . The default value is /usr/local .
-
- Example:
- # make PREFIX=/usr install
- # make PREFIX=/usr uninstall
+ $ make XPATH2_ENGINE=XQILLA
diff --git a/tools/s1kd-brexcheck/Makefile b/tools/s1kd-brexcheck/Makefile
index eb0f5375..1c1d1d87 100644
--- a/tools/s1kd-brexcheck/Makefile
+++ b/tools/s1kd-brexcheck/Makefile
@@ -25,9 +25,9 @@ PREFIX=/usr/local
INSTALL_PREFIX=$(PREFIX)/bin
INSTALL=install -Ds
-BREXCHECK_XPATH_ENGINE=LIBXML
+XPATH2_ENGINE=NONE
-ifeq ($(BREXCHECK_XPATH_ENGINE),SAXON)
+ifeq ($(XPATH2_ENGINE),SAXON)
ifeq ($(OS),Windows_NT)
SAXON_C_DIR=/cygdrive/c/Progra~1/Saxonica/SaxonHEC1.2.1
else
@@ -74,7 +74,7 @@ ifeq ($(BREXCHECK_XPATH_ENGINE),SAXON)
endif
endif
-ifeq ($(BREXCHECK_XPATH_ENGINE),XQILLA)
+ifeq ($(XPATH2_ENGINE),XQILLA)
XQILLA_OBJECTS+=xqilla/xqilla.o
SOURCE+=$(XQILLA_OBJECTS)
@@ -89,7 +89,7 @@ ifeq ($(BREXCHECK_XPATH_ENGINE),XQILLA)
endif
endif
-CFLAGS+=-DXPATH_ENGINE=$(BREXCHECK_XPATH_ENGINE)
+CFLAGS+=-DXPATH2_ENGINE=$(XPATH2_ENGINE)
all: $(OUTPUT)
diff --git a/tools/s1kd-brexcheck/README.md b/tools/s1kd-brexcheck/README.md
index 09a813cc..a06e0b4c 100644
--- a/tools/s1kd-brexcheck/README.md
+++ b/tools/s1kd-brexcheck/README.md
@@ -7,7 +7,8 @@ SYNOPSIS
========
s1kd-brexcheck [-b ] [-d ] [-I ] [-w ]
- [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?] [...]
+ [-X ] [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?]
+ [...]
DESCRIPTION
===========
@@ -112,6 +113,10 @@ Verbose mode. The success or failure of each test is printed explicitly.
-w, --severity-levels <file>
Specify a list of severity levels for business rules.
+-X, --xpath-version <version>
+Force the specified version of XPath to be used when evaluating the
+object paths of BREX rules.
+
-x, --xml
Output an XML report.
@@ -276,20 +281,22 @@ notation.
XPath support
-------------
-Supported XPath syntax depends on what XPath engine was selected at
-compile-time:
+By default, s1kd-brexcheck supports only XPath 1.0, with partial support
+for EXSLT functions.
-libxml (default)
-XPath 1.0 and partial support for EXSLT functions
+If experimental XPath 2.0 support is enabled at compile-time,
+s1kd-brexcheck will automatically choose a version of XPath based on the
+S1000D issue of the BREX data module:
-Saxon (experimental)
-XPath 1.0, 2.0 and 3.0
+3.0 and lower
+XPath 1.0
-XQilla (experimental)
-XPath 1.0 and 2.0
+4.0 and up
+XPath 2.0
-Information on which XPath engine is in use can be obtained from the
---version option.
+The -X (--xpath-version) option can be specified to force a particular
+version of XPath to be used regardless of issue. Information on which
+XPath versions are supported can be obtained from the --version option.
If the XPath given for the `` of a rule is invalid, the rule
will be ignored when validating objects. A warning will be printed to
@@ -311,6 +318,9 @@ One or more CSDB objects specified could not be read.
3
A referenced BREX data module could not be found.
+4
+The XPath version specified is unsupported.
+
5
The number of paths or CSDB objects specified exceeded the available
memory.
diff --git a/tools/s1kd-brexcheck/doc/DMC-S1KDTOOLS-A-04-00-00-00A-040A-D_EN-CA.XML b/tools/s1kd-brexcheck/doc/DMC-S1KDTOOLS-A-04-00-00-00A-040A-D_EN-CA.XML
index 4158abbb..7ff37c85 100644
--- a/tools/s1kd-brexcheck/doc/DMC-S1KDTOOLS-A-04-00-00-00A-040A-D_EN-CA.XML
+++ b/tools/s1kd-brexcheck/doc/DMC-S1KDTOOLS-A-04-00-00-00A-040A-D_EN-CA.XML
@@ -6,10 +6,10 @@
-
+
-
+
s1kd-brexcheck(1) | s1kd-tools
@@ -41,6 +41,9 @@
Add experimental XQilla support.
+
+ Add -X (--xpath-version) option.
+
@@ -52,8 +55,9 @@
SYNOPSIS
- ] [-d ] [-I ] [-w ]
- [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?] [...]]]>
+ ] [-d ] [-I ] [-w ]
+ [-X ] [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?]
+ [...]]]>
@@ -203,6 +207,12 @@
Specify a list of severity levels for business rules.
+
+ -X, --xpath-version <version>
+
+ Force the specified version of XPath to be used when evaluating the object paths of BREX rules.
+
+
-x, --xml
@@ -368,29 +378,24 @@
XPath support
-
- Supported XPath syntax depends on what XPath engine was selected at compile-time:
+ By default, s1kd-brexcheck supports only XPath 1.0, with partial support for EXSLT functions.
+
+ If experimental XPath 2.0 support is enabled at compile-time, s1kd-brexcheck will automatically choose a version of XPath based on the S1000D issue of the BREX data module:
- libxml (default)
+ 3.0 and lower
- XPath 1.0 and partial support for EXSLT functions
+ XPath 1.0
- Saxon (experimental)
+ 4.0 and up
- XPath 1.0, 2.0 and 3.0
-
-
-
- XQilla (experimental)
-
- XPath 1.0 and 2.0
+ XPath 2.0
- Information on which XPath engine is in use can be obtained from the --version option.
+ The -X (--xpath-version) option can be specified to force a particular version of XPath to be used regardless of issue. Information on which XPath versions are supported can be obtained from the --version option.
If the XPath given for the <objectPath> of a rule is invalid, the rule will be ignored when validating objects. A warning will be printed to stderr, and the XML report will contain an <xpathError> element for each error.
@@ -423,6 +428,12 @@
A referenced BREX data module could not be found.
+
+ 4
+
+ The XPath version specified is unsupported.
+
+
5
diff --git a/tools/s1kd-brexcheck/doc/s1kd-brexcheck.1 b/tools/s1kd-brexcheck/doc/s1kd-brexcheck.1
index 38a59ebd..6c0c0e75 100644
--- a/tools/s1kd-brexcheck/doc/s1kd-brexcheck.1
+++ b/tools/s1kd-brexcheck/doc/s1kd-brexcheck.1
@@ -1,6 +1,6 @@
.\" Automatically generated by Pandoc 2.3.1
.\"
-.TH "s1kd\-brexcheck" "1" "2020\-09\-04" "" "s1kd\-tools"
+.TH "s1kd\-brexcheck" "1" "2020\-09\-11" "" "s1kd\-tools"
.hy
.SH NAME
.PP
@@ -11,7 +11,8 @@ modules
.nf
\f[C]
s1kd\-brexcheck\ [\-b\ ]\ [\-d\ ]\ [\-I\ ]\ [\-w\ ]
-\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\-F|\-f]\ [\-BceLlNnopqrS[tu]sTvx^h?]\ [...]
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [\-X\ ]\ [\-F|\-f]\ [\-BceLlNnopqrS[tu]sTvx^h?]
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ [...]
\f[]
.fi
.SH DESCRIPTION
@@ -164,6 +165,12 @@ Specify a list of severity levels for business rules.
.RS
.RE
.TP
+.B \-X, \-\-xpath\-version
+Force the specified version of XPath to be used when evaluating the
+object paths of BREX rules.
+.RS
+.RE
+.TP
.B \-x, \-\-xml
Output an XML report.
.RS
@@ -377,26 +384,27 @@ If the \f[C]valueForm\f[] attribute is omitted, it will assume the value
is in the \f[C]"single"\f[] notation.
.SS XPath support
.PP
-Supported XPath syntax depends on what XPath engine was selected at
-compile\-time:
-.TP
-.B libxml (default)
-XPath 1.0 and partial support for EXSLT functions
-.RS
-.RE
+By default, s1kd\-brexcheck supports only XPath 1.0, with partial
+support for EXSLT functions.
+.PP
+If experimental XPath 2.0 support is enabled at compile\-time,
+s1kd\-brexcheck will automatically choose a version of XPath based on
+the S1000D issue of the BREX data module:
.TP
-.B Saxon (experimental)
-XPath 1.0, 2.0 and 3.0
+.B 3.0 and lower
+XPath 1.0
.RS
.RE
.TP
-.B XQilla (experimental)
-XPath 1.0 and 2.0
+.B 4.0 and up
+XPath 2.0
.RS
.RE
.PP
-Information on which XPath engine is in use can be obtained from the
-\-\-version option.
+The \-X (\-\-xpath\-version) option can be specified to force a
+particular version of XPath to be used regardless of issue.
+Information on which XPath versions are supported can be obtained from
+the \-\-version option.
.PP
If the XPath given for the \f[C]\f[] of a rule is invalid,
the rule will be ignored when validating objects.
@@ -424,6 +432,11 @@ A referenced BREX data module could not be found.
.RS
.RE
.TP
+.B 4
+The XPath version specified is unsupported.
+.RS
+.RE
+.TP
.B 5
The number of paths or CSDB objects specified exceeded the available
memory.
diff --git a/tools/s1kd-brexcheck/s1kd-brexcheck.c b/tools/s1kd-brexcheck/s1kd-brexcheck.c
index 0680845d..4d90d579 100644
--- a/tools/s1kd-brexcheck/s1kd-brexcheck.c
+++ b/tools/s1kd-brexcheck/s1kd-brexcheck.c
@@ -13,22 +13,26 @@
#include "brex.h"
#include "s1kd_tools.h"
-#define LIBXML 1
+#define NONE 1
#define SAXON 2
#define XQILLA 3
-#ifndef XPATH_ENGINE
-#define XPATH_ENGINE LIBXML
+#if XPATH2_ENGINE == 0
+#undef XPATH2_ENGINE
#endif
-#if XPATH_ENGINE == SAXON
+#ifndef XPATH2_ENGINE
+#define XPATH2_ENGINE NONE
+#endif
+
+#if XPATH2_ENGINE == SAXON
#include "saxon/saxon.h"
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
#include "xqilla/xqilla.h"
#endif
#define PROG_NAME "s1kd-brexcheck"
-#define VERSION "4.8.2"
+#define VERSION "4.9.0"
#define STRUCT_OBJ_RULE_PATH BAD_CAST \
"//contextRules[not(@rulesContext) or @rulesContext=$schema]//structureObjectRule|" \
@@ -39,7 +43,6 @@
#define W_PREFIX PROG_NAME ": WARNING: "
#define F_PREFIX PROG_NAME ": FAILED: "
#define S_PREFIX PROG_NAME ": SUCCESS: "
-#define I_PREFIX PROG_NAME ": INFO: "
/* Error messages. */
#define E_NODMOD E_PREFIX "Could not read file \"%s\".\n"
@@ -50,6 +53,7 @@
#define E_BREX_NOT_FOUND E_PREFIX "Could not find BREX data module: %s\n"
#define E_NOBREX E_PREFIX "No BREX data module found for %s.\n"
#define E_NOBREX_STDIN E_PREFIX "No BREX data module found for object on stdin.\n"
+#define E_BAD_XPATH_VERSION E_PREFIX "Unsupported XPath version: %s\n"
/* Warning messages. */
#define W_NOBREX W_PREFIX "%s does not reference a BREX data module.\n"
@@ -66,6 +70,7 @@
#define EXIT_BREX_ERROR 1
#define EXIT_BAD_DMODULE 2
#define EXIT_BREX_NOT_FOUND 3
+#define EXIT_BAD_XPATH_VERSION 4
#define EXIT_MAX_OBJS 5
/* URI for the XMLSchema-instance namespace. */
@@ -104,6 +109,9 @@ static bool ignore_empty = false;
/* Remove elements marked as "delete" before check. */
static bool rem_delete = false;
+/* Version of XPath to use. */
+enum xpath_version { DYNAMIC, XPATH_1, XPATH_2 };
+
struct opts {
enum verbosity verbosity;
@@ -137,7 +145,11 @@ struct opts {
*/
bool check_notations;
+ /* Assume object filenames do not include issue info. */
bool ignore_issue;
+
+ /* Force a version of XPath to be used. */
+ enum xpath_version xpath_version;
};
/* Return the first node in a set matching an XPath expression. */
@@ -724,9 +736,9 @@ static void register_functions(xmlXPathContextPtr ctx)
}
/* Register all namespaces applicable to a node in a new XPath context. */
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
static void register_namespaces(xmlXPathContextPtr ctx, void *saxon_xpath, xmlNodePtr node)
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
static void register_namespaces(xmlXPathContextPtr ctx, void *xqilla_ns_resolver, xmlNodePtr node)
#else
static void register_namespaces(xmlXPathContextPtr ctx, xmlNodePtr node)
@@ -740,10 +752,14 @@ static void register_namespaces(xmlXPathContextPtr ctx, xmlNodePtr node)
for (cur_ns = cur->nsDef; cur_ns; cur_ns = cur_ns->next) {
xmlXPathRegisterNs(ctx, cur_ns->prefix, cur_ns->href);
-#if XPATH_ENGINE == SAXON
- saxon_register_namespace(saxon_xpath, cur_ns->prefix, cur_ns->href);
-#elif XPATH_ENGINE == XQILLA
- xqilla_register_namespace(xqilla_ns_resolver, cur_ns->prefix, cur_ns->href);
+#if XPATH2_ENGINE == SAXON
+ if (saxon_xpath) {
+ saxon_register_namespace(saxon_xpath, cur_ns->prefix, cur_ns->href);
+ }
+#elif XPATH2_ENGINE == XQILLA
+ if (xqilla_ns_resolver) {
+ xqilla_register_namespace(xqilla_ns_resolver, cur_ns->prefix, cur_ns->href);
+ }
#endif
}
@@ -752,9 +768,9 @@ static void register_namespaces(xmlXPathContextPtr ctx, xmlNodePtr node)
}
/* Check the context rules of a BREX DM against a CSDB object. */
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr doc, const char *fname, const char *brexfname, xmlNodePtr documentNode, struct opts *opts, void *saxon_processor, void *saxon_node)
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr doc, const char *fname, const char *brexfname, xmlNodePtr documentNode, struct opts *opts, void *xqilla_doc)
#else
static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr doc, const char *fname, const char *brexfname, xmlNodePtr documentNode, struct opts *opts)
@@ -778,10 +794,22 @@ static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr d
xmlNodePtr brDecisionRef, objectPath, objectUse;
xmlChar *allowedObjectFlag, *path, *use, *brdp;
-#if XPATH_ENGINE == SAXON
- void *xpath_processor = saxon_new_xpath_processor(saxon_processor);
-#elif XPATH_ENGINE == XQILLA
- void *xqilla_ns_resolver = xqilla_create_ns_resolver(xqilla_doc);
+#if XPATH2_ENGINE == SAXON
+ void *xpath_processor;
+
+ if (saxon_processor) {
+ xpath_processor = saxon_new_xpath_processor(saxon_processor);
+ } else {
+ xpath_processor = NULL;
+ }
+#elif XPATH2_ENGINE == XQILLA
+ void *xqilla_ns_resolver;
+
+ if (xqilla_doc) {
+ xqilla_ns_resolver = xqilla_create_ns_resolver(xqilla_doc);
+ } else {
+ xqilla_ns_resolver = NULL;
+ }
#endif
brDecisionRef = firstXPathNode(brex_doc, rules->nodeTab[i], "brDecisionRef");
@@ -796,14 +824,22 @@ static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr d
context = xmlXPathNewContext(doc);
register_functions(context);
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
register_namespaces(context, xpath_processor, objectPath);
- object = saxon_eval_xpath(saxon_processor, xpath_processor, saxon_node, path, context);
-#elif XPATH_ENGINE == XQILLA
+ if (xpath_processor) {
+ object = saxon_eval_xpath(saxon_processor, xpath_processor, saxon_node, path, context);
+ } else {
+ object = xmlXPathEval(path, context);
+ }
+#elif XPATH2_ENGINE == XQILLA
register_namespaces(context, xqilla_ns_resolver, objectPath);
- object = xqilla_eval_xpath(xqilla_doc, xqilla_ns_resolver, path, context);
+ if (xqilla_ns_resolver) {
+ object = xqilla_eval_xpath(xqilla_doc, xqilla_ns_resolver, path, context);
+ } else {
+ object = xmlXPathEval(path, context);
+ }
#else
register_namespaces(context, objectPath);
@@ -887,7 +923,7 @@ static int check_brex_rules(xmlDocPtr brex_doc, xmlNodeSetPtr rules, xmlDocPtr d
}
}
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
saxon_free_xpath_processor(xpath_processor);
#endif
/* FIXME: If the XPath expression was invalid, xmlXPathFreeObject doesn't
@@ -1208,10 +1244,43 @@ static void print_valid_fnames(xmlNodePtr node)
}
}
+#if XPATH2_ENGINE != NONE
+/* Determine whether the S1000D issue of a BREX DM means it may require
+ * XPath 2.0 to evaluate its rules.
+ */
+static bool brex_requires_xpath2(xmlDocPtr brex, struct opts *opts)
+{
+ xmlChar *issue;
+ bool requires_xpath2;
+
+ switch (opts->xpath_version) {
+ case XPATH_1: return false;
+ case XPATH_2: return true;
+ case DYNAMIC: break;
+ }
+
+ issue = xmlGetNsProp(xmlDocGetRootElement(brex),
+ BAD_CAST "noNamespaceSchemaLocation",
+ BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
+
+ /* These issues of S1000D only required XPath 1.0. */
+ if (xmlStrncmp(issue, BAD_CAST "http://www.s1000d.org/S1000D_2-0", 32) == 0) requires_xpath2 = false;
+ else if (xmlStrncmp(issue, BAD_CAST "http://www.s1000d.org/S1000D_2-1", 32) == 0) requires_xpath2 = false;
+ else if (xmlStrncmp(issue, BAD_CAST "http://www.s1000d.org/S1000D_2-2", 32) == 0) requires_xpath2 = false;
+ else if (xmlStrncmp(issue, BAD_CAST "http://www.s1000d.org/S1000D_2-3", 32) == 0) requires_xpath2 = false;
+ else if (xmlStrncmp(issue, BAD_CAST "http://www.s1000d.org/S1000D_3-0", 32) == 0) requires_xpath2 = false;
+ else requires_xpath2 = true;
+
+ xmlFree(issue);
+
+ return requires_xpath2;
+}
+#endif
+
/* Check context, SNS, and notation rules of BREX DMs against a CSDB object. */
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fnames)[PATH_MAX], int num_brex_fnames, xmlNodePtr brexCheck, struct opts *opts, void *saxon_processor)
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fnames)[PATH_MAX], int num_brex_fnames, xmlNodePtr brexCheck, struct opts *opts, void *xqilla_impl)
#else
static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fnames)[PATH_MAX], int num_brex_fnames, xmlNodePtr brexCheck, struct opts *opts)
@@ -1229,9 +1298,9 @@ static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fname
xmlDocPtr validtree = NULL;
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
void *saxon_node;
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
void *xqilla_parser;
void *xqilla_doc;
#endif
@@ -1247,9 +1316,9 @@ static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fname
rem_delete_elems(dmod_doc);
}
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
saxon_node = saxon_new_node(saxon_processor, dmod_doc);
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
xqilla_parser = xqilla_create_parser(xqilla_impl);
xqilla_doc = xqilla_create_doc(xqilla_impl, xqilla_parser, dmod_doc);
#endif
@@ -1275,6 +1344,9 @@ static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fname
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
int status;
+#if XPATH2_ENGINE != NONE
+ bool use_xpath2;
+#endif
brex_doc = load_brex(brex_fnames[i], dmod_doc);
@@ -1290,10 +1362,23 @@ static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fname
result = xmlXPathEvalExpression(STRUCT_OBJ_RULE_PATH, context);
-#if XPATH_ENGINE == SAXON
- status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, saxon_processor, saxon_node);
-#elif XPATH_ENGINE == XQILLA
- status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, xqilla_doc);
+#if XPATH2_ENGINE != NONE
+ /* Determine if the BREX rules should be evaluated with XPath 2.0. */
+ use_xpath2 = brex_requires_xpath2(brex_doc, opts);
+#endif
+
+#if XPATH2_ENGINE == SAXON
+ if (use_xpath2) {
+ status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, saxon_processor, saxon_node);
+ } else {
+ status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, NULL, NULL);
+ }
+#elif XPATH2_ENGINE == XQILLA
+ if (use_xpath2) {
+ status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, xqilla_doc);
+ } else {
+ status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts, NULL);
+ }
#else
status = check_brex_rules(brex_doc, result->nodesetval, dmod_doc, docname, brex_fnames[i], documentNode, opts);
#endif
@@ -1327,9 +1412,9 @@ static int check_brex(xmlDocPtr dmod_doc, const char *docname, char (*brex_fname
xmlFreeDoc(validtree);
}
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
saxon_free_node(saxon_node);
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
xqilla_free_parser(xqilla_parser);
#endif
@@ -1495,6 +1580,24 @@ static void add_config_to_report(xmlNodePtr brexCheck, struct opts *opts)
}
}
+/* Determine XPath version of user-supplied string. */
+static void set_xpath_version(struct opts *opts, const char *str)
+{
+ if (strcmp(str, "1.0") == 0) {
+ opts->xpath_version = XPATH_1;
+#if XPATH2_ENGINE != NONE
+ } else if (strcmp(str, "2.0") == 0) {
+ opts->xpath_version = XPATH_2;
+#endif
+ } else {
+ if (opts->verbosity > SILENT) {
+ fprintf(stderr, E_BAD_XPATH_VERSION, str);
+ }
+
+ exit(EXIT_BAD_XPATH_VERSION);
+ }
+}
+
#ifdef LIBS1KD
typedef enum {
S1KD_BREXCHECK_VALUES = 1,
@@ -1522,6 +1625,8 @@ static void init_opts(struct opts *opts, int options)
opts->strict_sns = optset(options, S1KD_BREXCHECK_STRICT_SNS);
opts->unstrict_sns = optset(options, S1KD_BREXCHECK_UNSTRICT_SNS);
opts->check_notations = optset(options, S1KD_BREXCHECK_NOTATIONS);
+ opts->ignore_issue = false;
+ opts->xpath_version = DYNAMIC;
}
static void free_opts(struct opts *opts)
@@ -1538,14 +1643,21 @@ int s1kdDocCheckDefaultBREX(xmlDocPtr doc, int options, xmlDocPtr *report)
xmlNodePtr node;
const char *brex_dmc;
struct opts opts;
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
void *saxon_processor, *saxon_node;
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
void *xqilla_impl, *xqilla_parser, *xqilla_doc;
#endif
+#if XPATH2_ENGINE != NONE
+ bool use_xpath2;
+#endif
init_opts(&opts, options);
+#if XPATH2_ENGINE != NONE
+ use_xpath2 = brex_requires_xpath2(brex, &opts);
+#endif
+
rep = xmlNewDoc(BAD_CAST "1.0");
node = xmlNewNode(NULL, BAD_CAST "brexCheck");
xmlDocSetRootElement(rep, node);
@@ -1560,23 +1672,31 @@ int s1kdDocCheckDefaultBREX(xmlDocPtr doc, int options, xmlDocPtr *report)
ctx = xmlXPathNewContext(brex);
obj = xmlXPathEvalExpression(BAD_CAST "//structureObjectRule", ctx);
-#if XPATH_ENGINE == SAXON
- saxon_processor = saxon_new_processor();
- saxon_node = saxon_new_node(saxon_processor, doc);
+#if XPATH2_ENGINE == SAXON
+ if (use_xpath2) {
+ saxon_processor = saxon_new_processor();
+ saxon_node = saxon_new_node(saxon_processor, doc);
- err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, saxon_processor, saxon_node);
+ err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, saxon_processor, saxon_node);
- saxon_free_node(saxon_node);
- saxon_free_processor(saxon_processor);
-#elif XPATH_ENGINE == XQILLA
- xqilla_impl = xqilla_initialize();
- xqilla_parser = xqilla_create_parser(xqilla_impl);
- xqilla_doc = xqilla_create_doc(xqilla_impl, xqilla_parser, doc);
+ saxon_free_node(saxon_node);
+ saxon_free_processor(saxon_processor);
+ } else {
+ err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, NULL, NULL);
+ }
+#elif XPATH2_ENGINE == XQILLA
+ if (use_xpath2) {
+ xqilla_impl = xqilla_initialize();
+ xqilla_parser = xqilla_create_parser(xqilla_impl);
+ xqilla_doc = xqilla_create_doc(xqilla_impl, xqilla_parser, doc);
- err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, xqilla_doc);
+ err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, xqilla_doc);
- xqilla_free_parser(xqilla_parser);
- xqilla_terminate();
+ xqilla_free_parser(xqilla_parser);
+ xqilla_terminate();
+ } else {
+ err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts, NULL);
+ }
#else
err = check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex_dmc, node, &opts);
#endif
@@ -1621,14 +1741,21 @@ int s1kdDocCheckBREX(xmlDocPtr doc, xmlDocPtr brex, int options, xmlDocPtr *repo
xmlXPathObjectPtr obj;
xmlNodePtr node;
struct opts opts;
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
void *saxon_processor, *saxon_node;
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
void *xqilla_impl, *xqilla_parser, *xqilla_doc;
#endif
+#if XPATH2_ENGINE != NONE
+ bool use_xpath2;
+#endif
init_opts(&opts, options);
+#if XPATH2_ENGINE != NONE
+ use_xpath2 = brex_requires_xpath2(brex, &opts);
+#endif
+
rep = xmlNewDoc(BAD_CAST "1.0");
node = xmlNewNode(NULL, BAD_CAST "brexCheck");
xmlDocSetRootElement(rep, node);
@@ -1664,23 +1791,31 @@ int s1kdDocCheckBREX(xmlDocPtr doc, xmlDocPtr brex, int options, xmlDocPtr *repo
xmlFreeDoc(notationRulesDoc);
}
-#if XPATH_ENGINE == SAXON
- saxon_processor = saxon_new_processor();
- saxon_node = saxon_new_node(saxon_processor, doc);
+#if XPATH2_ENGINE == SAXON
+ if (use_xpath2) {
+ saxon_processor = saxon_new_processor();
+ saxon_node = saxon_new_node(saxon_processor, doc);
- err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, saxon_processor, saxon_node);
+ err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, saxon_processor, saxon_node);
- saxon_free_node(saxon_node);
- saxon_free_processor(saxon_processor);
-#elif XPATH_ENGINE == XQILLA
- xqilla_impl = xqilla_initialize();
- xqilla_parser = xqilla_create_parser(xqilla_impl);
- xqilla_doc = xqilla_create_doc(xqilla_impl, xqilla_parser, doc);
+ saxon_free_node(saxon_node);
+ saxon_free_processor(saxon_processor);
+ } else {
+ err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, NULL, NULL);
+ }
+#elif XPATH2_ENGINE == XQILLA
+ if (use_xpath2) {
+ xqilla_impl = xqilla_initialize();
+ xqilla_parser = xqilla_create_parser(xqilla_impl);
+ xqilla_doc = xqilla_create_doc(xqilla_impl, xqilla_parser, doc);
- err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, xqilla_doc);
+ err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, xqilla_doc);
- xqilla_free_parser(xqilla_parser);
- xqilla_terminate();
+ xqilla_free_parser(xqilla_parser);
+ xqilla_terminate();
+ } else {
+ err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts, NULL);
+ }
#else
err += check_brex_rules(brex, obj->nodesetval, doc, doc->URL, brex->URL, node, &opts);
#endif
@@ -1721,7 +1856,7 @@ int s1kdCheckBREX(const char *object_xml, int object_size, const char *brex_xml,
/* Show usage message. */
static void show_help(void)
{
- puts("Usage: " PROG_NAME " [-b ] [-d ] [-I ] [-w ] [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?] [...]");
+ puts("Usage: " PROG_NAME " [-b ] [-d ] [-I ] [-w ] [-X ] [-F|-f] [-BceLlNnopqrS[tu]sTvx^h?] [...]");
puts("");
puts("Options:");
puts(" -B, --default-brex Use the default BREX.");
@@ -1746,6 +1881,7 @@ static void show_help(void)
puts(" -T, --summary Print a summary of the check.");
puts(" -v, --verbose Verbose mode.");
puts(" -w, --severity-levels List of severity levels.");
+ puts(" -X, --xpath-version Force the version of XPath that will be used.");
puts(" -x, --xml XML output.");
puts(" -^, --remove-deleted Check with elements marked as \"delete\" removed.");
puts(" --version Show version information.");
@@ -1753,7 +1889,7 @@ static void show_help(void)
}
/* Show version information. */
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
static void show_version(void *saxon_processor)
#else
static void show_version(void)
@@ -1761,15 +1897,15 @@ static void show_version(void)
{
printf("%s (s1kd-tools) %s\n", PROG_NAME, VERSION);
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
printf("Using libxml %s, libxslt %s, libexslt %s and %s\n", xmlParserVersion, xsltEngineVersion, exsltLibraryVersion, saxon_version(saxon_processor));
- puts("XPath engine: Saxon");
-#elif XPATH_ENGINE == XQILLA
+ puts("XPath support: 1.0 (libxml), 2.0 (Saxon)");
+#elif XPATH2_ENGINE == XQILLA
printf("Using libxml %s, libxslt %s, libexslt %s and Xerces-C %s + XQilla\n", xmlParserVersion, xsltEngineVersion, exsltLibraryVersion, xqilla_version());
- puts("XPath engine: XQilla");
+ puts("XPath support: 1.0 (libxml), 2.0 (XQilla)");
#else
printf("Using libxml %s, libxslt %s and libexslt %s\n", xmlParserVersion, xsltEngineVersion, exsltLibraryVersion);
- puts("XPath engine: libxml");
+ puts("XPath support: 1.0 (libxml)");
#endif
}
@@ -1807,10 +1943,11 @@ int main(int argc, char *argv[])
/* strict_sns */ false,
/* unstrict_sns */ false,
/* check_notations */ false,
- /* ignore_issue */ false
+ /* ignore_issue */ false,
+ /* xpath_version */ DYNAMIC
};
- const char *sopts = "Bb:eI:xvqslw:StupFfNncLTrd:o^h?";
+ const char *sopts = "Bb:eI:xvqslw:StupFfNncLTrd:oX:^h?";
struct option lopts[] = {
{"version" , no_argument , 0, 0},
{"help" , no_argument , 0, 'h'},
@@ -1838,17 +1975,18 @@ int main(int argc, char *argv[])
{"summary" , no_argument , 0, 'T'},
{"recursive" , no_argument , 0, 'r'},
{"output-valid" , no_argument , 0, 'o'},
+ {"xpath-version" , required_argument, 0, 'X'},
{"remove-deleted" , no_argument , 0, '^'},
LIBXML2_PARSE_LONGOPT_DEFS
{0, 0, 0, 0}
};
int loptind = 0;
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
void *saxon_processor;
saxon_processor = saxon_new_processor();
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
void *xqilla_impl;
xqilla_impl = xqilla_initialize();
@@ -1861,7 +1999,7 @@ int main(int argc, char *argv[])
switch (c) {
case 0:
if (strcmp(lopts[loptind].name, "version") == 0) {
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
show_version(saxon_processor);
#else
show_version();
@@ -1903,6 +2041,7 @@ int main(int argc, char *argv[])
case 'r': recursive_search = true; break;
case 'o': output_tree = true; break;
case 'e': ignore_empty = true; break;
+ case 'X': set_xpath_version(&opts, optarg); break;
case '^':
rem_delete = true;
break;
@@ -2028,9 +2167,9 @@ int main(int argc, char *argv[])
dmod_fnames, num_dmod_fnames, dmod_doc, &opts);
}
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
status += check_brex(dmod_doc, dmod_fnames[i], brex_fnames, num_brex_fnames, brexCheck, &opts, saxon_processor);
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
status += check_brex(dmod_doc, dmod_fnames[i], brex_fnames, num_brex_fnames, brexCheck, &opts, xqilla_impl);
#else
status += check_brex(dmod_doc, dmod_fnames[i], brex_fnames, num_brex_fnames, brexCheck, &opts);
@@ -2077,10 +2216,10 @@ int main(int argc, char *argv[])
free(dmod_fnames);
free(search_dir);
-#if XPATH_ENGINE == SAXON
+#if XPATH2_ENGINE == SAXON
saxon_free_processor(saxon_processor);
saxon_cleanup();
-#elif XPATH_ENGINE == XQILLA
+#elif XPATH2_ENGINE == XQILLA
xqilla_terminate();
#endif
diff --git a/tools/s1kd-brexcheck/saxon/README.md b/tools/s1kd-brexcheck/saxon/README.md
index 831ceafa..14b54e38 100644
--- a/tools/s1kd-brexcheck/saxon/README.md
+++ b/tools/s1kd-brexcheck/saxon/README.md
@@ -6,5 +6,5 @@ To set up Saxon/C for use with s1kd-brexcheck, do the following:
2. Enable Saxon when building:
```
- $ make BREXCHECK_XPATH_ENGINE=SAXON
+ $ make XPATH2_ENGINE=SAXON
```
diff --git a/tools/s1kd-brexcheck/xqilla/README.md b/tools/s1kd-brexcheck/xqilla/README.md
index ca59adfd..2f2fac60 100644
--- a/tools/s1kd-brexcheck/xqilla/README.md
+++ b/tools/s1kd-brexcheck/xqilla/README.md
@@ -9,5 +9,5 @@ To set up XQilla for use with s1kd-brexcheck, do the following:
2. Enable XQilla when building:
```
- $ make BREXCHECK_XPATH_ENGINE=XQILLA
+ $ make XPATH2_ENGINE=XQILLA
```