• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Keine Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

XML catalogue of packages which are available for installation, using the mingw-get installer.


Commit MetaInfo

Revision1292b6d6cf2cb84292afc805986dd45579c1f871 (tree)
Zeit2013-10-08 21:42:49
AutorKeith Marshall <keithmarshall@user...>
CommiterKeith Marshall

Log Message

Implement an XML validation test suite.

Ändern Zusammenfassung

Diff

--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
11 2013-10-08 Keith Marshall <keithmarshall@users.sourceforge.net>
22
3+ Implement an XML validation test suite.
4+
5+ * tests: New directory.
6+ * tests/configure.ac tests/Makefile.in: New files.
7+ * tests/xmlcheck.cpp tests/pkgspec.xsd: Likewise.
8+
9+2013-10-08 Keith Marshall <keithmarshall@users.sourceforge.net>
10+
311 Delegate version assignment to VERSION.m4 auxiliary file.
412
513 * VERSION.m4: New file.
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,78 @@
1+# @configure_input@
2+#
3+# $Id$
4+#
5+# Written by Keith Marshall <keithmarshall@users.sourceforge.net>
6+# Copyright (C) 2013, MinGW.org Project
7+#
8+#
9+# Makefile template for generating mingw-get distribution manifests.
10+#
11+# Project: @PACKAGE_TARNAME@
12+# Version: @PACKAGE_VERSION@
13+#
14+#
15+# This is free software. Permission is granted to copy, modify and
16+# redistribute this software, under the provisions of the GNU General
17+# Public License, Version 3, (or, at your option, any later version),
18+# as published by the Free Software Foundation; see the file COPYING
19+# for licensing details.
20+#
21+# Note, in particular, that this software is provided "as is", in the
22+# hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
23+# even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
24+# PARTICULAR PURPOSE. Under no circumstances will the author, or the
25+# MinGW Project, accept liability for any damages, however caused,
26+# arising from the use of this software.
27+#
28+VPATH = @srcdir@
29+vpath VERSION.m4 @srcdir@/..
30+
31+CXX = @CXX@
32+CXXFLAGS = @CXXFLAGS@
33+LDFLAGS = @LDFLAGS@
34+LIBS = @LIBS@
35+
36+EXEEXT = @EXEEXT@
37+OBJEXT = @OBJEXT@
38+
39+srcdir = @srcdir@
40+xml_datarootdir = ${srcdir}/..
41+
42+XMLCHECK =
43+
44+check: @XERCES_C_TOOLS@
45+ ./xmlcheck$(EXEEXT) ${srcdir}/pkgspec.xsd ${xml_datarootdir}/*/*.xml \
46+ 2> xmlcheck.log && rm -f xmlcheck.log \
47+ || { cat xmlcheck.log; exit 1; }
48+
49+no-xerces-c-tools:
50+ @for msg in $(NO_XERCES_C_TOOLS_MSG); do echo $$msg; done; false
51+
52+NO_XERCES_C_TOOLS_MSG = "" \
53+ "This test suite requires the Xerces-C++ SDK, but it appears that" \
54+ "this has not been installed on your system." "" \
55+ "Please install a copy of this SDK, which is compatible with your" \
56+ "system C++ compiler, if you wish to run this test suite." ""
57+
58+xerces-c-tools: xmlcheck$(EXEEXT)
59+xmlcheck$(EXEEXT): xmlcheck.$(OBJEXT)
60+ $(CXX) $(CXXFLAGS) -o $@ $(LDFLAGS) $^ $(LIBS)
61+
62+sinclude *.d
63+%.$(OBJEXT): %.cpp
64+ $(CXX) -MMD -MP -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $<
65+
66+configure: configure.ac VERSION.m4
67+ cd ${srcdir}; autoconf
68+
69+config.status: configure
70+ ./config.status --recheck
71+
72+Makefile: config.status Makefile.in
73+ ./config.status
74+
75+clean:
76+ rm -f *.$(OBJEXT) xmlcheck$(EXEEXT)
77+
78+# $RCSfile$: end of file
--- /dev/null
+++ b/tests/configure.ac
@@ -0,0 +1,46 @@
1+# configure.ac -*- autoconf -*- vim: filetype=config
2+#
3+# $Id$
4+#
5+# Written by Keith Marshall <keithmarshall@users.sourceforge.net>
6+# Copyright (C) 2013, MinGW.org Project
7+#
8+#
9+# Configuration script for mingw-dist validation suite
10+#
11+#
12+# This is free software. Permission is granted to copy, modify and
13+# redistribute this software, under the provisions of the GNU General
14+# Public License, Version 3, (or, at your option, any later version),
15+# as published by the Free Software Foundation; see the file COPYING
16+# for licensing details.
17+#
18+# Note, in particular, that this software is provided "as is", in the
19+# hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
20+# even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
21+# PARTICULAR PURPOSE. Under no circumstances will the author, or the
22+# MinGW Project, accept liability for any damages, however caused,
23+# arising from the use of this software.
24+#
25+ m4_include([../VERSION.m4])
26+ AC_INIT([mingw-dist-tests],__VERSION__,[http://mingw.org/reporting_bugs])
27+#
28+# Building the test suite driver program requires a C++ compiler,
29+# (which must emit binary code to run on the build platform).
30+#
31+ AC_PROG_CXX
32+#
33+# The test suite is heavily dependent on the Xerces-C++ SDK; check, to
34+# ensure that this is installed.
35+#
36+ AC_CHECK_LIB([xerces-c],[main])
37+ AS_IF([test x"$ac_cv_lib_xerces_c_main" = xyes],dnl
38+ [XERCES_C_TOOLS=xerces-c-tools],[XERCES_C_TOOLS=no-xerces-c-tools])dnl
39+ AC_SUBST([XERCES_C_TOOLS])
40+#
41+# Configure output comprises a simple makefile.
42+#
43+ AC_CONFIG_FILES([Makefile])
44+ AC_OUTPUT
45+#
46+# $RCSfile$: end of file
--- /dev/null
+++ b/tests/pkgspec.xsd
@@ -0,0 +1,413 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3+ <!--
4+ $Id$
5+
6+ XSDL schema for validation of mingw-get package specifications.
7+
8+ Written by Keith Marshall <keithmarshall@users.sourceforge.net>
9+ Copyright (C) 2013, MinGW.org Project
10+
11+
12+ This file is part of the mingw-dist catalogue validation suite.
13+
14+ This is free software. Permission is granted to copy, modify and
15+ redistribute this software, under the provisions of the GNU General
16+ Public License, Version 3, (or, at your option, any later version),
17+ as published by the Free Software Foundation; see the file COPYING
18+ for licensing details.
19+
20+ Note, in particular, that this software is provided "as is", in the
21+ hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
22+ even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
23+ PARTICULAR PURPOSE. Under no circumstances will the author, or the
24+ MinGW Project, accept liability for any damages, however caused,
25+ arising from the use of this software.
26+
27+
28+ Note to maintainers, (because this may seem counter intuitive, and
29+ thus may be eminently forgettable): whilst the structure of any XML
30+ document demands that attributes be specified in the opening tag of
31+ their associated element, and thus they PRECEDE the element content,
32+ XSDL requires that they be declared AFTER the corresponding content
33+ model; please ensure that their declarations are correctly placed
34+ within this XSDL schema.
35+ -->
36+
37+ <xs:element name="software-distribution" type="specification-document" />
38+ <!--
39+ The package specification document root is always an XML element
40+ named "software-distribution", which must conform to the following
41+ type definition
42+ -->
43+ <xs:complexType name="specification-document">
44+ <xs:sequence>
45+ <!--
46+ The entire specification comprises a sequence of at most three
47+ optionally repeating section types; unless it is omitted...
48+ -->
49+ <xs:element name="package-group-hierarchy" minOccurs="0">
50+ <!--
51+ ...this must appear as the first section; only one instance
52+ is permitted.
53+ -->
54+ <xs:complexType>
55+ <xs:sequence maxOccurs="unbounded">
56+ <!--
57+ Within the package group hierarchy, at least one package
58+ group must be specified. Additional group specifications
59+ may be added, without limit; all must conform to the type
60+ definition, as specified below.
61+ -->
62+ <xs:element name="package-group" type="package-group-definition" />
63+ </xs:sequence>
64+ </xs:complexType>
65+ </xs:element>
66+ <!--
67+ When present, a package group hierarchy specification is typically
68+ followed by one or more instances of...
69+ -->
70+ <xs:element name="package-list" minOccurs="0" maxOccurs="unbounded">
71+ <!--
72+ ...this; it is optional, but when present, all instances must
73+ follow the package group hierarchy specification, (if any), and
74+ must precede any "package collection" specification.
75+ -->
76+ <xs:complexType>
77+ <!--
78+ This is an "attribute only" element. The "catalogue" attribute
79+ must be specified; it represents the name of a further XML file
80+ to be included within the specification document, omitting both
81+ any directory path, and the ".xml" file name suffix.
82+ -->
83+ <xs:attribute name="catalogue" type="xs:string" use="required" />
84+ <!--
85+ The specification author typically does NOT specify the "issue"
86+ attribute; it is inserted automatically by the "mingw-dist" build
87+ system, as an indicator to mingw-get when the catalogue named by
88+ the "catalogue" attribute should be updated.
89+ -->
90+ <xs:attribute name="issue" type="serial-number" />
91+ </xs:complexType>
92+ </xs:element>
93+ <!--
94+ Typically specified in isolation, (i.e. entirely separated from any
95+ package group hierarchy or package list specification), the final
96+ section which may appear in the specification document is...
97+ -->
98+ <xs:element name="package-collection" minOccurs="0" maxOccurs="unbounded">
99+ <!--
100+ ...this. Although any number of instances may appear in a single
101+ specification document, most commonly, each document will specify
102+ only one package collection, which itself comprises...
103+ -->
104+ <xs:complexType>
105+ <!--
106+ ...a group of child elements, as defined below, specifying the
107+ set of packages which are included in this collection.
108+ -->
109+ <xs:group ref="package-collection-specification" />
110+ <!--
111+ All of the individual packages in any one collection MUST
112+ be assigned to a common installation "subsystem", which is
113+ identified by this required attribute.
114+ -->
115+ <xs:attribute name="subsystem" type="xs:string" use="required" />
116+ </xs:complexType>
117+ </xs:element>
118+ </xs:sequence>
119+ <!--
120+ The specification document also supports three attributes: the "project"
121+ and "host" attributes are optional; they are provided primarily as an aid
122+ to documenting the origin of the specified package collection, but they
123+ are not actually used by mingw-get.
124+ -->
125+ <xs:attribute name="project" type="xs:string" default="MinGW" />
126+ <xs:attribute name="home" type="xs:anyURI" default="http://www.mingw.org" />
127+ <!--
128+ On the other hand, the "issue" attribute is required; it takes a string
129+ value, conforming to the type definition below; in the source context of
130+ a mingw-dist catalogue build, it should be specified using the template
131+ form for the value; other contexts should use the YYYYMMDDNN form.
132+ -->
133+ <xs:attribute name="issue" type="serial-number" use="required" />
134+ </xs:complexType>
135+
136+ <xs:simpleType name="serial-number">
137+ <!--
138+ This specialization of the XSDL string type is to be used to specify the
139+ value for the "issue" attribute, which is required in every specification
140+ document. It may be either be the explicit "@YYYYMMDDNN@" substitution
141+ template, as used in mingw-dist source documents, or any ten character
142+ alpha-numeric pattern derived from this template.
143+ -->
144+ <xs:restriction base="xs:string">
145+ <xs:pattern value="(@YYYYMMDDNN@)|([0-9A-Z]{10})" />
146+ </xs:restriction>
147+ </xs:simpleType>
148+
149+ <xs:complexType name="package-group-definition">
150+ <!--
151+ Defines the structure of the elements used to specify package groups,
152+ within the package group hierarchy section of the specification document.
153+ Elements of this type may repeat any number of times, both within this
154+ context, and recursively nested within other package groups.
155+ -->
156+ <xs:sequence minOccurs="0" maxOccurs="unbounded">
157+ <xs:element name="package-group" type="package-group-definition" />
158+ </xs:sequence>
159+ <!--
160+ Every package group must be named; mingw-get uses the value of the "name"
161+ attribute as a label, to create a tree-view display representation of the
162+ package group hierarchy, in the left hand pane of the GUI client window.
163+ -->
164+ <xs:attribute name="name" type="xs:string" use="required" />
165+ <!--
166+ The optional "expand" attribute provides a mechanism for specifying those
167+ levels of a nested package group hierarchy which are to be shown expanded,
168+ in the initial rendition of the tree-view display.
169+ -->
170+ <xs:attribute name="expand" type="xs:boolean" />
171+ </xs:complexType>
172+
173+ <xs:group name="package-group-association-and-description">
174+ <!--
175+ Provides the mechanism for defining package to package group associations,
176+ allowing multiple associations to be specified, and intermingled with any
177+ number of package description elements, at the beginning of any individual
178+ package specification.
179+ -->
180+ <xs:sequence>
181+ <xs:choice minOccurs="0" maxOccurs="unbounded">
182+ <xs:element name="affiliate">
183+ <!--
184+ Defines a single package to package group association, in terms of
185+ a single attribute only specification element...
186+ -->
187+ <xs:complexType>
188+ <xs:attribute name="group" type="xs:string" />
189+ </xs:complexType>
190+ </xs:element>
191+ <!--
192+ ...whilst this allows "description" blocks to be interspersed among
193+ repeating "affiliate" specifications.
194+ -->
195+ <xs:element name="description" type="package-description" />
196+ </xs:choice>
197+ </xs:sequence>
198+ </xs:group>
199+
200+ <xs:complexType name="package-description">
201+ <!--
202+ Defines the structure of a "description" block as a container for a
203+ sequence of one or more "paragraph" blocks...
204+ -->
205+ <xs:sequence>
206+ <xs:element name="paragraph" maxOccurs="unbounded" />
207+ </xs:sequence>
208+ <!--
209+ ...optionally qualified by "lang" and/or "title" attributes.
210+ -->
211+ <xs:attribute name="lang" type="xs:string" default="en" />
212+ <xs:attribute name="title" type="xs:string" />
213+ </xs:complexType>
214+
215+ <xs:group name="package-collection-specification">
216+ <xs:sequence>
217+ <!--
218+ Defines the sequence of XML elements which are required to properly
219+ specify any package group collection.
220+ -->
221+ <xs:element name="download-host">
222+ <xs:complexType>
223+ <!--
224+ The first is always a specification for the URL whence all packages
225+ in the collection may be downloaded; it is declared as a string type
226+ because it is specified in a template format, which may violate the
227+ constraints of the XSDL anyURI type, e.g.:
228+
229+ <download-host uri="http://host.domain.com/packages/%F" />
230+
231+ where "%F" is substituted, at download time, by the actual name of
232+ the archive file wich is to be downloaded.
233+
234+ Note: only one template may be specified for any package collection;
235+ thus all packages in any collection MUST be served from one common
236+ hosting domain.
237+ -->
238+ <xs:attribute name="uri" type="xs:string" use="required" />
239+ </xs:complexType>
240+ </xs:element>
241+ <!--
242+ The download host specification may be followed by an optional sequence
243+ of package group association specifications. These must conform to the
244+ format defined above, where it may be seen that they comprise any number
245+ of "affiliate" and "description" elements, in arbitrary order. If any
246+ of these are specified here, they apply to every package subsequently
247+ included within the collection.
248+ -->
249+ <xs:group ref="package-group-association-and-description" />
250+ <xs:choice maxOccurs="unbounded">
251+ <!--
252+ The principal content of any package collection comprises an arbitrary
253+ number of "package" specification elements.
254+ -->
255+ <xs:element name="package">
256+ <xs:complexType>
257+ <xs:sequence>
258+ <!--
259+ Each package specification begins with an optional description,
260+ and an arbitrary set of package group association declarations.
261+ -->
262+ <xs:group ref="package-group-association-and-description" />
263+ <!--
264+ This must be followed by an arbitray sequence of one or more
265+ "source", "licence", "component", or "action" specifications.
266+ -->
267+ <xs:choice maxOccurs="unbounded">
268+ <xs:group ref="source-or-licence-archive-reference" />
269+ <xs:element name="component" type="component-specification" />
270+ <xs:element name="action" type="action-script" />
271+ </xs:choice>
272+ </xs:sequence>
273+ <!--
274+ Each package MUST be named; it may also be assigned to the class
275+ of "virtual" packages, so identifying it as a meta-package, and it
276+ may also be identified by a list of aliases.
277+ -->
278+ <xs:attribute name="name" type="xs:string" use="required" />
279+ <xs:attribute name="class" type="package-class" />
280+ <xs:attribute name="alias" type="xs:string" />
281+ </xs:complexType>
282+ </xs:element>
283+ <!--
284+ Actions may also be specified within the package-collection scope, in
285+ which case they apply to all packages, and component packages, which
286+ are declared within the collection.
287+ -->
288+ <xs:element name="action" type="action-script" />
289+ </xs:choice>
290+ </xs:sequence>
291+ </xs:group>
292+
293+ <xs:simpleType name="package-class">
294+ <!--
295+ Any package may be specified as a meta-package, by assigning it a "class"
296+ attribute value of "virtual"; specification of this attribute is optional,
297+ but no other value is permitted.
298+ -->
299+ <xs:restriction base="xs:string">
300+ <xs:pattern value="virtual" />
301+ </xs:restriction>
302+ </xs:simpleType>
303+
304+ <xs:complexType name="component-specification">
305+ <!--
306+ Each "package" should be subdivided into one or more "component" packages,
307+ each of which may bear its own individual description and/or package group
308+ associations. Each "component" package should also define a sequence of
309+ "release" specifications, optionally qualified by specifications of any
310+ dependencies which are common to all releases of the "component" package,
311+ and any actions which should be performed when installing or removing any
312+ release of the "component" package.
313+ -->
314+ <xs:choice maxOccurs="unbounded">
315+ <xs:group ref="package-group-association-and-description" />
316+ <xs:element name="release" type="release-specification" />
317+ <xs:element name="requires" type="dependency-specification" />
318+ <xs:element name="action" type="action-script" />
319+ </xs:choice>
320+ <!--
321+ Every "component" package MUST be classified; however, the choice of
322+ "class" name is unrestricted.
323+ -->
324+ <xs:attribute name="class" type="xs:string" use="required" />
325+ </xs:complexType>
326+
327+ <xs:complexType name="release-specification">
328+ <!--
329+ Each individual release of any component package must be specified by its
330+ own "release" specification element; this may be qualified by a "download"
331+ specification, (for cases where the actual archive file name differs from
332+ the canonical "tarname", or is "none" in the case of a meta-release, for
333+ which the container "package" element cannot be declared as "virtual");
334+ each "release" may also specify its own set of dependencies, and/or its
335+ own specific "source" and/or "licence" archive associations.
336+ -->
337+ <xs:choice minOccurs="0" maxOccurs="unbounded">
338+ <xs:element name="download" type="tarname-reference" />
339+ <xs:element name="requires" type="dependency-specification" />
340+ <xs:group ref="source-or-licence-archive-reference" />
341+ </xs:choice>
342+ <!--
343+ Every "release" MUST be identified by a canonical "tarname" attribute.
344+ -->
345+ <xs:attribute ref="tarname" use="required" />
346+ </xs:complexType>
347+
348+ <xs:complexType name="action-script" mixed="true">
349+ <!--
350+ Any action is specified as Lua script, appearing as textual content within
351+ the body of the "action" element; it also requires a specification for its
352+ "class" attribute, to identify the context in which it is to be executed.
353+ -->
354+ <xs:attribute name="class" type="action-class" use="required" />
355+ </xs:complexType>
356+
357+ <xs:simpleType name="action-class">
358+ <!--
359+ The context in which any specified action is to be executed must be one of
360+ "pre-install", "post-install", "pre-remove", or "post-remove".
361+ -->
362+ <xs:restriction base="xs:string">
363+ <xs:pattern value="(pre|post)-(install|remove)" />
364+ </xs:restriction>
365+ </xs:simpleType>
366+
367+ <xs:group name="source-or-licence-archive-reference">
368+ <!--
369+ "source" and "licence" elements are simple "attribute only" elements, each
370+ of which requires only a "tarname" attribute; note that the spelling which
371+ is required for the "licence" element uses the noun form, as prescribed by
372+ the Oxford Dictionary of World English; use of the US English form, where
373+ noun and verb are both spelled as "license" is NOT supported.
374+ -->
375+ <xs:choice>
376+ <xs:element name="source" type="tarname-reference" />
377+ <xs:element name="licence" type="tarname-reference" />
378+ </xs:choice>
379+ </xs:group>
380+
381+ <xs:complexType name="tarname-reference">
382+ <!--
383+ When any element accepts a "tarname" attribute, then specification of that
384+ attribute is mandatory.
385+ -->
386+ <xs:attribute ref="tarname" use="required" />
387+ </xs:complexType>
388+ <!--
389+ The "tarname" attribute is a simple string type; it should match a specific
390+ pattern, but for the time being, we do not attempt to verify it.
391+ -->
392+ <xs:attribute name="tarname" type="xs:string" />
393+
394+ <xs:complexType name="dependency-specification">
395+ <!--
396+ Any "requires" specification MUST include one or more of the following
397+ attributes, to declare an equality or a range dependency. It may be noted
398+ that, while a range specification requires two such attributes, there will
399+ be some combinations which will be mutually inconsistent; unfortunately,
400+ XSDL provides no mechanism to filter out such combinations.
401+ -->
402+ <xs:attribute name="lt" type="xs:string" />
403+ <xs:attribute name="le" type="xs:string" />
404+ <xs:attribute name="eq" type="xs:string" />
405+ <xs:attribute name="ge" type="xs:string" />
406+ <xs:attribute name="gt" type="xs:string" />
407+ </xs:complexType>
408+
409+</xs:schema>
410+
411+<!-- vim: set nocompatible fileformat=unix: -->
412+<!-- vim: set smartindent shiftwidth=2 expandtab textwidth=80 wrap: -->
413+<!-- $RCSfile$: end of file -->
--- /dev/null
+++ b/tests/xmlcheck.cpp
@@ -0,0 +1,409 @@
1+/*
2+ * xmlcheck.cpp
3+ *
4+ * $Id$
5+ *
6+ * Adapted from load-grammar-dom.cxx
7+ * Written by Boris Kolpackov <boris@codesynthesis.com>
8+ * Assigned, by the author, to the public domain
9+ *
10+ * This program uses Xerces-C++ DOM parser to load a set of schema files
11+ * and then to validate a set of XML documents against these schemas. To
12+ * build this program you will need Xerces-C++ 3.0.0 or later. For more
13+ * information, see:
14+ *
15+ * http: *www.codesynthesis.com/~boris/blog/2010/03/15/validating-external-schemas-xerces-cxx/
16+ *
17+ *
18+ * Adaptation by Keith Marshall <keithmarshall@users.sourceforge.net>
19+ * Copyright (C) 2013, MinGW.org Project
20+ *
21+ * This is free software. Permission is granted to copy, modify and
22+ * redistribute this software, under the provisions of the GNU General
23+ * Public License, Version 3, (or, at your option, any later version),
24+ * as published by the Free Software Foundation; see the file COPYING
25+ * for licensing details.
26+ *
27+ * Note, in particular, that this software is provided "as is", in the
28+ * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
29+ * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
30+ * PARTICULAR PURPOSE. Under no circumstances will the author, or the
31+ * MinGW Project, accept liability for any damages, however caused,
32+ * arising from the use of this software.
33+ *
34+ */
35+#include <cstdio>
36+#include <string>
37+#include <memory> /* for std::auto_ptr */
38+#include <cstddef> /* for std::size_t */
39+
40+#include <libgen.h> /* for basename() */
41+
42+#include <xercesc/util/XMLUni.hpp>
43+#include <xercesc/util/XMLString.hpp>
44+#include <xercesc/util/PlatformUtils.hpp>
45+
46+#include <xercesc/dom/DOM.hpp>
47+
48+#include <xercesc/validators/common/Grammar.hpp>
49+#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
50+
51+using namespace std;
52+using namespace xercesc;
53+
54+#if _XERCES_VERSION < 30000
55+/* We need at least Xerces-C++ version 3.0.0
56+ */
57+# error Xerces-C++ version >= 3.0.0 is required!
58+
59+#elif _XERCES_VERSION >= 30100
60+/* We may wish to exploit some features which were not introduced
61+ * until Xerces-C++ version 3.1.0
62+ */
63+# define IF_XERCES_30100_PLUS( STATEMENT ) STATEMENT
64+
65+#else
66+/* We cannot use Xerces-C++ version 3.1.0 features; make them no-op.
67+ */
68+# define IF_XERCES_30100_PLUS( STATEMENT )
69+#endif
70+
71+class error_handler: public DOMErrorHandler
72+{
73+ /* A locally defined class for capture of fault conditions, as
74+ * reported by our DOM parsers.
75+ */
76+ public:
77+ /* Constructor.
78+ */
79+ error_handler( const char *rel): source(rel),
80+ first_report(true), new_document(true), failed(false){}
81+
82+ /* Method to access recorded error condition status.
83+ */
84+ bool has_failed() const { return failed; }
85+
86+ /* Method to reset recorded status, in preparation for
87+ * parsing a new document.
88+ */
89+ void reset(){ new_document = true; failed = false; }
90+
91+ /* Method to handle error conditions, on behalf of our
92+ * DOM parsers.
93+ */
94+ virtual bool handleError( const xercesc::DOMError& );
95+
96+ private:
97+ /* The type of XML input being parsed, recorded when we
98+ * consturct the error handler for binding to a particular
99+ * DOM parser.
100+ */
101+ const char *source;
102+
103+ /* Recording for error condition status.
104+ */
105+ bool first_report, new_document, failed;
106+};
107+
108+bool
109+error_handler::handleError( const xercesc::DOMError& condition )
110+{
111+ /* Implementation of the error handler, which we will use to capture
112+ * status, and report abnormal conditions detected by our DOM parsers.
113+ */
114+ bool warn = condition.getSeverity() == DOMError::DOM_SEVERITY_WARNING;
115+
116+ /* Record detection of any condition which is more severe than
117+ * a simple warning.
118+ */
119+ if( ! warn ) failed = true;
120+
121+ /* Identify the location, within the current XML schema or document
122+ * file, where the abnormality has been detected.
123+ */
124+ DOMLocator* loc( condition.getLocation() );
125+
126+ /* When this is the first abnormality detected within the current
127+ * XML schema or document file...
128+ */
129+ if( new_document )
130+ {
131+ /* ...but we've previously reported abnormalities within another
132+ * input file, then separate the current report from diagnostics
133+ * relating to that other file...
134+ */
135+ if( ! first_report ) fputc( '\n', stderr );
136+
137+ /* ...then, regardless of whatever may have gone before, format
138+ * and emit a report header to identify the current file.
139+ */
140+ char *uri = XMLString::transcode( loc->getURI() );
141+ fprintf( stderr, "Problem Report:\n%s: %s\n", source, uri );
142+ XMLString::release( &uri );
143+
144+ /* Record that we've now emitted a report header and diagnostic
145+ * for the current XML input file.
146+ */
147+ first_report = new_document = false;
148+ }
149+
150+ /* Whether we added a new report header, or not, we still have a
151+ * diagnostic message to emit.
152+ */
153+ char* msg = XMLString::transcode( condition.getMessage() );
154+ fprintf( stderr, "%d:%d: %s: %s\n", loc->getLineNumber(),
155+ loc->getColumnNumber(), warn ? "WARNING" : "ERROR", msg
156+ );
157+ XMLString::release( &msg );
158+
159+ /* Finally, we return "true" to tell the DOM parser that we've
160+ * handled the error, and that it should continue parsing.
161+ */
162+ return true;
163+}
164+
165+static bool
166+insufficient_arguments( bool status, const char *program_pathname )
167+{
168+ /* Diagnostic routine to report a lack of any command arguments
169+ * to specify the XML documents which are to be validated.
170+ */
171+ if( status )
172+ {
173+ /* The "status" flag indicates an abnormal condition...
174+ *
175+ * We want to call "basename()" on the passed "program_pathname";
176+ * while this is likely safe, it MAY try to modify the input string,
177+ * so create a temporary working copy...
178+ */
179+ char progname[1 + strlen( program_pathname )];
180+
181+ /* ...then format and emit an appropriate diagnostic message.
182+ */
183+ strcpy( progname, program_pathname );
184+ fprintf( stderr, "%s: no XML documents specified for validation\n"
185+ "usage: %s [schema.xsd ...] document.xml ...\n", basename( progname ),
186+ program_pathname
187+ );
188+ }
189+ /* Irrespective of condition, we echo back the input state.
190+ */
191+ return status;
192+}
193+
194+DOMLSParser*
195+create_parser( XMLGrammarPool* pool )
196+{
197+ /* Helper function, to instantiate a DOM parser with "LS", (load and
198+ * save), capability, (although we intend to use only "load").
199+ */
200+ const XMLCh ls_id[] = { chLatin_L, chLatin_S, chNull };
201+
202+ /* Locate a DOM implementation, providing the requisite "LS" feature.
203+ */
204+ DOMImplementation* impl(
205+ DOMImplementationRegistry::getDOMImplementation( ls_id ) );
206+
207+ /* Instantiate a parser, based on this DOM implementation.
208+ */
209+ DOMLSParser* parser(
210+ impl->createLSParser(
211+ DOMImplementationLS::MODE_SYNCHRONOUS,
212+ 0,
213+ XMLPlatformUtils::fgMemoryManager,
214+ pool ) );
215+
216+ /* Retrieve a pointer to its configuration data...
217+ */
218+ DOMConfiguration* conf( parser->getDomConfig() );
219+
220+ /* ...so we may apply this commonly useful configuration.
221+ */
222+ conf->setParameter( XMLUni::fgDOMComments, false );
223+ conf->setParameter( XMLUni::fgDOMDatatypeNormalization, true );
224+ conf->setParameter( XMLUni::fgDOMElementContentWhitespace, false );
225+ conf->setParameter( XMLUni::fgDOMNamespaces, true );
226+ conf->setParameter( XMLUni::fgDOMEntities, false );
227+
228+ /* Enable validation.
229+ */
230+ conf->setParameter( XMLUni::fgDOMValidate, true );
231+ conf->setParameter( XMLUni::fgXercesSchema, true );
232+ conf->setParameter( XMLUni::fgXercesSchemaFullChecking, false );
233+
234+ /* Use the loaded grammar during parsing.
235+ */
236+ conf->setParameter( XMLUni::fgXercesUseCachedGrammarInParse, true );
237+
238+ /* Don't load schemas from any other source (e.g., from XML document's
239+ * xsi:schemaLocation attributes).
240+ */
241+ conf->setParameter( XMLUni::fgXercesLoadSchema, false );
242+
243+ /* Xerces-C++ 3.1.0 is the first version with working support for
244+ * multiple import.
245+ */
246+ IF_XERCES_30100_PLUS(
247+ conf->setParameter( XMLUni::fgXercesHandleMultipleImports, true )
248+ );
249+
250+ /* We will release the DOM document ourselves.
251+ */
252+ conf->setParameter( XMLUni::fgXercesUserAdoptsDOMDocument, true );
253+
254+ /* Return a pointer to the instantiated parser.
255+ */
256+ return parser;
257+}
258+
259+static inline int
260+validation_status( int argc, char **argv )
261+{
262+ int retcode = 0;
263+
264+ /* Initialize a grammer pool, for use by our parser instances.
265+ */
266+ MemoryManager* mm( XMLPlatformUtils::fgMemoryManager );
267+ auto_ptr<XMLGrammarPool> gp( new XMLGrammarPoolImpl( mm ) );
268+
269+ /* Load the schema definitions into the grammar pool.
270+ */
271+ int argind = 1;
272+ {
273+ /* Instantiate a parser for the schema definition file(s).
274+ */
275+ DOMLSParser* parser( create_parser( gp.get() ) );
276+
277+ /* Initialize an error handler for the schema context,
278+ * and bind it to the schema file parser.
279+ */
280+ error_handler eh( "XML Schema" );
281+ parser->getDomConfig()->setParameter( XMLUni::fgDOMErrorHandler, &eh );
282+
283+ /* Scan command arguments, left to right, to identify any XML schema
284+ * files which we are expected to interpret.
285+ */
286+ do { const char *source = argv[argind]; size_t extent = strlen( source );
287+ if( (extent > 4) && (strcasecmp( source + extent - 4, ".xsd" ) == 0) )
288+ {
289+ /* We have a "*.xsd" file to parse; do so, loading the grammar...
290+ */
291+ if( !parser->loadGrammar( source, Grammar::SchemaGrammarType, true ) )
292+ {
293+ /* ...but complain, and bail out, if loading fails...
294+ */
295+ fprintf( stderr, "%s: error: unable to load\n", source );
296+ retcode = 1;
297+ }
298+ if( eh.has_failed() )
299+ /*
300+ * ...or if any schema parsing error was encountered.
301+ */
302+ retcode = 1;
303+ }
304+ else
305+ /* We've exhausted the "*.xsd" file references; break out of
306+ * the scanning loop, without further ceremony.
307+ */
308+ break;
309+
310+ /* Continue for the next "*.xsd" file, if any, provided there
311+ * have been no schema abormalities detected thus far.
312+ */
313+ } while( (retcode == 0) && (++argind < argc) );
314+
315+ /* We're finished with our schema parser; release its resource pool.
316+ */
317+ parser->release();
318+ }
319+
320+ /* Before proceeding to parse any XML documents, check that any
321+ * specified XML schemas have been loaded successfully.
322+ */
323+ if( retcode == 0 )
324+ {
325+ /* It's okay to proceed, but it would be pointless to do so...
326+ */
327+ if( insufficient_arguments( argind >= argc, *argv ) )
328+ /*
329+ * ...when there are no remaining arguments to specify any
330+ * XML documents for checking; in this case, bail out.
331+ */
332+ return 1;
333+
334+ /* Lock the grammar pool. This is necessary if we plan to use the
335+ * same grammar pool in multiple threads (this way we can reuse the
336+ * same grammar in multiple parsers). Locking the pool disallows any
337+ * modifications to the pool, such as an attempt by one of the threads
338+ * to cache additional schemas.
339+ */
340+ gp->lockPool();
341+
342+ /* Instantiate a new parser, to process the XML documents.
343+ */
344+ DOMLSParser* parser( create_parser( gp.get() ) );
345+
346+ /* Initialize an error handler for the XML document context,
347+ * and bind it to the new parser.
348+ */
349+ error_handler eh( "XML Document" );
350+ parser->getDomConfig()->setParameter( XMLUni::fgDOMErrorHandler, &eh );
351+
352+ /* Process all remaining arguments, as references to XML documents.
353+ */
354+ while( argind < argc )
355+ {
356+ /* Reset the error handler state, prior to loading each document.
357+ */
358+ eh.reset();
359+ DOMDocument* doc( parser->parseURI( argv[argind++] ) );
360+
361+ /* In this application, all we care about is that the document
362+ * can be successfully read by our validating parser; if we did
363+ * read it successfully, we have no further use for it, se we
364+ * may simply set it aside.
365+ */
366+ if( doc ) doc->release();
367+
368+ /* If any error occurred, while parsing the current document,
369+ * the error handler will have recorded it; we need to capture
370+ * that state here, for our eventual return code.
371+ */
372+ if( eh.has_failed() ) retcode = 1;
373+ }
374+ /* When all specified documents have been validated, we are done
375+ * with our parser, so we may release its resource pool.
376+ */
377+ parser->release();
378+ }
379+ /* Report back, with the cumulative status from XML document parsing.
380+ */
381+ return retcode;
382+}
383+
384+int
385+main( int argc, char **argv )
386+{
387+ /* Fewer than one argument, after the command verb itself,
388+ * is not useful; complain, and bail out.
389+ */
390+ if( insufficient_arguments( argc < 2, *argv ) )
391+ return 1;
392+
393+ /* We must initialize Xerces-C++, before we can use it.
394+ */
395+ XMLPlatformUtils::Initialize();
396+
397+ /* Determine the validation status for all specified XML documents,
398+ * with respect to any specified XML schema definitions.
399+ */
400+ int retcode = validation_status( argc, argv );
401+
402+ /* Shut down the Xerces-C++ subsystem, before returning the resultant
403+ * validation status code to the operating system.
404+ */
405+ XMLPlatformUtils::Terminate();
406+ return retcode;
407+}
408+
409+/* $RCSfile$: end of file */