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. - <verbatimText>BREXCHECK_XPATH_ENGINE</verbatimText> + <verbatimText>PREFIX</verbatimText> + + 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 + + + + + <verbatimText>XPATH2_ENGINE</verbatimText> - 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 - - - - - <verbatimText>PREFIX</verbatimText> - - 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 ```