XML catalogue of packages which are available for installation, using the mingw-get installer.
Revision | 1292b6d6cf2cb84292afc805986dd45579c1f871 (tree) |
---|---|
Zeit | 2013-10-08 21:42:49 |
Autor | Keith Marshall <keithmarshall@user...> |
Commiter | Keith Marshall |
Implement an XML validation test suite.
@@ -1,5 +1,13 @@ | ||
1 | 1 | 2013-10-08 Keith Marshall <keithmarshall@users.sourceforge.net> |
2 | 2 | |
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 | + | |
3 | 11 | Delegate version assignment to VERSION.m4 auxiliary file. |
4 | 12 | |
5 | 13 | * VERSION.m4: New file. |
@@ -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 |
@@ -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 |
@@ -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 --> |
@@ -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 */ |