1 """The ``lxml.isoschematron`` package implements ISO Schematron support on top
2 of the pure-xslt 'skeleton' implementation.
3 """
4
5 import sys
6 import os.path
7 from lxml import etree as _etree
8
9
10
11 try:
12 unicode
13 except NameError:
14
15 unicode = str
16 try:
17 basestring
18 except NameError:
19
20 basestring = str
21
22
23 __all__ = ['extract_xsd', 'extract_rng', 'iso_dsdl_include',
24 'iso_abstract_expand', 'iso_svrl_for_xslt1',
25 'svrl_validation_errors', 'schematron_schema_valid',
26 'stylesheet_params', 'Schematron']
27
28
29
30
31
32 XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema"
33 RELAXNG_NS = "http://relaxng.org/ns/structure/1.0"
34 SCHEMATRON_NS = "http://purl.oclc.org/dsdl/schematron"
35 SVRL_NS = "http://purl.oclc.org/dsdl/svrl"
36
37
38
39 _schematron_root = '{%s}schema' % SCHEMATRON_NS
40 _xml_schema_root = '{%s}schema' % XML_SCHEMA_NS
41 _resources_dir = os.path.join(os.path.dirname(__file__), 'resources')
42
43
44
45 extract_xsd = _etree.XSLT(_etree.parse(
46 os.path.join(_resources_dir, 'xsl', 'XSD2Schtrn.xsl')))
47 extract_rng = _etree.XSLT(_etree.parse(
48 os.path.join(_resources_dir, 'xsl', 'RNG2Schtrn.xsl')))
49 iso_dsdl_include = _etree.XSLT(_etree.parse(
50 os.path.join(_resources_dir, 'xsl', 'iso-schematron-xslt1',
51 'iso_dsdl_include.xsl')))
52 iso_abstract_expand = _etree.XSLT(_etree.parse(
53 os.path.join(_resources_dir, 'xsl', 'iso-schematron-xslt1',
54 'iso_abstract_expand.xsl')))
55 iso_svrl_for_xslt1 = _etree.XSLT(_etree.parse(
56 os.path.join(_resources_dir,
57 'xsl', 'iso-schematron-xslt1', 'iso_svrl_for_xslt1.xsl')))
58
59
60
61 svrl_validation_errors = _etree.XPath(
62 '//svrl:failed-assert', namespaces={'svrl': SVRL_NS})
63
64
65
66 schematron_schema_valid = _etree.RelaxNG(
67 file=os.path.join(_resources_dir, 'rng', 'iso-schematron.rng'))
71 """Convert keyword args to a dictionary of stylesheet parameters.
72 XSL stylesheet parameters must be XPath expressions, i.e.:
73
74 * string expressions, like "'5'"
75 * simple (number) expressions, like "5"
76 * valid XPath expressions, like "/a/b/text()"
77
78 This function converts native Python keyword arguments to stylesheet
79 parameters following these rules:
80 If an arg is a string wrap it with XSLT.strparam().
81 If an arg is an XPath object use its path string.
82 If arg is None raise TypeError.
83 Else convert arg to string.
84 """
85 result = {}
86 for key, val in kwargs.items():
87 if isinstance(val, basestring):
88 val = _etree.XSLT.strparam(val)
89 elif val is None:
90 raise TypeError('None not allowed as a stylesheet parameter')
91 elif not isinstance(val, _etree.XPath):
92 val = unicode(val)
93 result[key] = val
94 return result
95
99 """Return a copy of paramsDict, updated with kwargsDict entries, wrapped as
100 stylesheet arguments.
101 kwargsDict entries with a value of None are ignored.
102 """
103
104 paramsDict = dict(paramsDict)
105 for k, v in kwargsDict.items():
106 if v is not None:
107 paramsDict[k] = v
108 paramsDict = stylesheet_params(**paramsDict)
109 return paramsDict
110
113 """An ISO Schematron validator.
114
115 Pass a root Element or an ElementTree to turn it into a validator.
116 Alternatively, pass a filename as keyword argument 'file' to parse from
117 the file system.
118
119 Schematron is a less well known, but very powerful schema language.
120 The main idea is to use the capabilities of XPath to put restrictions on
121 the structure and the content of XML documents.
122
123 The standard behaviour is to fail on ``failed-assert`` findings only
124 (``ASSERTS_ONLY``). To change this, you can either pass a report filter
125 function to the ``error_finder`` parameter (e.g. ``ASSERTS_AND_REPORTS``
126 or a custom ``XPath`` object), or subclass isoschematron.Schematron for
127 complete control of the validation process.
128
129 Built on the Schematron language 'reference' skeleton pure-xslt
130 implementation, the validator is created as an XSLT 1.0 stylesheet using
131 these steps:
132
133 0) (Extract from XML Schema or RelaxNG schema)
134 1) Process inclusions
135 2) Process abstract patterns
136 3) Compile the schematron schema to XSLT
137
138 The ``include`` and ``expand`` keyword arguments can be used to switch off
139 steps 1) and 2).
140 To set parameters for steps 1), 2) and 3) hand parameter dictionaries to the
141 keyword arguments ``include_params``, ``expand_params`` or
142 ``compile_params``.
143 For convenience, the compile-step parameter ``phase`` is also exposed as a
144 keyword argument ``phase``. This takes precedence if the parameter is also
145 given in the parameter dictionary.
146
147 If ``store_schematron`` is set to True, the (included-and-expanded)
148 schematron document tree is stored and available through the ``schematron``
149 property.
150 If ``store_xslt`` is set to True, the validation XSLT document tree will be
151 stored and can be retrieved through the ``validator_xslt`` property.
152 With ``store_report`` set to True (default: False), the resulting validation
153 report document gets stored and can be accessed as the ``validation_report``
154 property.
155
156 Here is a usage example::
157
158 >>> from lxml import etree
159 >>> from lxml.isoschematron import Schematron
160
161 >>> schematron = Schematron(etree.XML('''
162 ... <schema xmlns="http://purl.oclc.org/dsdl/schematron" >
163 ... <pattern id="id_only_attribute">
164 ... <title>id is the only permitted attribute name</title>
165 ... <rule context="*">
166 ... <report test="@*[not(name()='id')]">Attribute
167 ... <name path="@*[not(name()='id')]"/> is forbidden<name/>
168 ... </report>
169 ... </rule>
170 ... </pattern>
171 ... </schema>'''),
172 ... error_finder=Schematron.ASSERTS_AND_REPORTS)
173
174 >>> xml = etree.XML('''
175 ... <AAA name="aaa">
176 ... <BBB id="bbb"/>
177 ... <CCC color="ccc"/>
178 ... </AAA>
179 ... ''')
180
181 >>> schematron.validate(xml)
182 False
183
184 >>> xml = etree.XML('''
185 ... <AAA id="aaa">
186 ... <BBB id="bbb"/>
187 ... <CCC/>
188 ... </AAA>
189 ... ''')
190
191 >>> schematron.validate(xml)
192 True
193 """
194
195
196 _domain = _etree.ErrorDomains.SCHEMATRONV
197 _level = _etree.ErrorLevels.ERROR
198 _error_type = _etree.ErrorTypes.SCHEMATRONV_ASSERT
199
200
201 ASSERTS_ONLY = svrl_validation_errors
202 ASSERTS_AND_REPORTS = _etree.XPath(
203 '//svrl:failed-assert | //svrl:successful-report',
204 namespaces={'svrl': SVRL_NS})
205
219
220
221
222
223 _extract_xsd = extract_xsd
224 _extract_rng = extract_rng
225 _include = iso_dsdl_include
226 _expand = iso_abstract_expand
227 _compile = iso_svrl_for_xslt1
228
229
230
231
232 _validation_errors = ASSERTS_ONLY
233
234 - def __init__(self, etree=None, file=None, include=True, expand=True,
235 include_params={}, expand_params={}, compile_params={},
236 store_schematron=False, store_xslt=False, store_report=False,
237 phase=None, error_finder=ASSERTS_ONLY):
289
314
315 @property
317 """ISO-schematron schema document (None if object has been initialized
318 with store_schematron=False).
319 """
320 return self._schematron
321
322 @property
324 """ISO-schematron skeleton implementation XSLT validator document (None
325 if object has been initialized with store_xslt=False).
326 """
327 return self._validator_xslt
328
329 @property
331 """ISO-schematron validation result report (None if result-storing has
332 been turned off).
333 """
334 return self._validation_report
335