pax_global_header00006660000000000000000000000064142114034460014511gustar00rootroot0000000000000052 comment=1c9d1ea7b6458b6263b05a722d62eb22f2bb23a9 xmlschema-1.10.0/000077500000000000000000000000001421140344600135515ustar00rootroot00000000000000xmlschema-1.10.0/.coveragerc000066400000000000000000000003561421140344600156760ustar00rootroot00000000000000[run] branch = True source = xmlschema/ omit = xmlschema/testing/* xmlschema/aliases.py [report] exclude_lines = pragma: no cover raise NotImplementedError() in self._etree_iterparse\( in PyElementTree.iterparse\(xmlschema-1.10.0/.github/000077500000000000000000000000001421140344600151115ustar00rootroot00000000000000xmlschema-1.10.0/.github/workflows/000077500000000000000000000000001421140344600171465ustar00rootroot00000000000000xmlschema-1.10.0/.github/workflows/test-xmlschema.yml000066400000000000000000000031541421140344600226320ustar00rootroot00000000000000name: xmlschema on: push: branches: [master, develop] pull_request: branches: [master, develop] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.7, 3.8, 3.9, "3.10", "pypy-3.8"] exclude: - os: macos-latest python-version: 3.7 - os: windows-latest python-version: 3.7 - os: macos-latest python-version: 3.8 - os: windows-latest python-version: 3.8 steps: - uses: actions/checkout@v2 - name: Install additional development libraries for building lxml if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == 'pypy-3.8' }} run: sudo apt-get update && sudo apt-get install libxml2-dev libxslt-dev python-dev - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install pip and setuptools run: | python -m pip install --upgrade pip pip install setuptools - name: Test with unittest run: | pip install lxml jinja2 pip install . python -m unittest - name: Lint with flake8 run: | pip install flake8 flake8 xmlschema --max-line-length=100 --statistics - name: Lint with mypy if: ${{ matrix.python-version != 'pypy-3.8' }} run: | pip install mypy==0.931 elementpath==2.5.0 lxml-stubs mypy --show-error-codes xmlschema xmlschema-1.10.0/.gitignore000066400000000000000000000002721421140344600155420ustar00rootroot00000000000000*.pyc *.pyo *~ *.so *.egg-info *.json *.zip .idea/ .mypy_cache/ .tox/ .eggs/ .coverage* !.coveragerc .ipynb_checkpoints/ doc/_*/ dist/ build/ development/ test_cases/ !tests/test_cases/ xmlschema-1.10.0/.readthedocs.yml000066400000000000000000000001441421140344600166360ustar00rootroot00000000000000build: image: latest python: version: 3.7 pip_install: true extra_requirements: - docs xmlschema-1.10.0/CHANGELOG.rst000066400000000000000000000504661421140344600156050ustar00rootroot00000000000000********* CHANGELOG ********* `v1.10.0`_ (2022-03-07) ====================== * Add 'nonlocal' option to *defuse* argument of `XMLResource` (also for schema classes) * Add 'none' option to *allow* argument of `XMLResource` * Fix too strict parsing on XSD annotations (issue #287) * Drop support for Python 3.6 `v1.9.2`_ (2021-12-23) ====================== * Fix for global simple type naming (issue #278) `v1.9.1`_ (2021-12-08) ====================== * Improve error reporting for encoded data (issue #275) * Fix attribute duplicates in attribute group (issue #276) * Add process_skipped optional argument to decoding/encoding `v1.9.0`_ (2021-11-30) ====================== * Add iter_decode() to document level API * Enhance XMLResource class adding usage of pathlib.Path objects for source and base_url arguments * Fix for issue #273 `v1.8.2`_ (2021-11-11) ====================== * Fix for issues #266 and #268 * Fix type annotation of XMLSchema source argument (issue #230) `v1.8.1`_ (2021-10-20) ====================== * Near compliance with strict type annotations * Removed ModelGroup class, merged with XsdGroup * Some optimizations and fixes from static analysis `v1.8.0`_ (2021-09-27) ====================== * Refactor XMLSchemaMeta deprecating BUILDER attribute * Extend type annotations to package API * Add static typing tests with checked mypy runs `v1.7.1`_ (2021-09-03) ====================== * Activate mypy checks for package * Fix for issues #257 and #259 `v1.7.0`_ (2021-08-02) ====================== * Make XSD annotation parsing lazy * Add lazy annotations to schema instances * Add get_annotation() method to multiple-facets classes (issue #255) `v1.6.4`_ (2021-06-09) ====================== * Add testing config for Python 3.10 (Tox and CI) * Fix internal _PurePath class with Python 3.10 (issue #251) * Remove redundant xmlns="" declaration when encoding with lxml (issue #252) `v1.6.3`_ (2021-06-07) ====================== * Refactor normalize_url() using pathlib.PurePath * Support UNC paths (issue #246) * Fix API docs (issue #248) `v1.6.2`_ (2021-05-03) ====================== * Fix for issue #245 (key/keyref with dynamic types) * Change default decoding of mixed content with only text to a string instead of a dictionary (issue #242) `v1.6.1`_ (2021-04-11) ====================== * Add multi-source initialization and add_schema() to schema class * Add bytes strings to accepted XML sources (issue #238) `v1.6.0`_ (2021-04-06) ====================== * XML data bindings and code generators are now considered stable * Add arguments 'max_depth' and 'extra_validator' to validation methods * Enhance decoding with 'value_hook' argument `v1.5.3`_ (2021-03-14) ====================== * Remove unnecessary bindings with schema proxy from ElementPathMixin to avoid conflicts when schema is used by an XPath 3 parser * Fix schema logger (issue #228) `v1.5.2`_ (2021-03-04) ====================== * Improve empty content checking * Fix simple content restriction of xs:complexType * Fix facets retrieving for xs:complexType with simple content `v1.5.1`_ (2021-02-11) ====================== * Optimize NamespaceView read-only mapping * Add experimental XML data bindings with a DataBindingConverter * Add experimental PythonGenerator for static codegen with Jinja2 `v1.5.0`_ (2021-02-05) ====================== * Add DataElement class for creating objects with schema bindings * Add DataElementConverter for decode to structured objects * Add an experimental abstract base class for building jinja2 based code generators (jinja2 as an optional dependency) `v1.4.2`_ (2021-01-24) ====================== * Add decoding of binary datatypes (xs:hexBinary and xs:base64Binary) * Fix encoding from string values for some builtin datatypes (decimal, binary, duration and datetime) `v1.4.1`_ (2020-12-24) ====================== * Include the pull request #220 (fix xml.etree import) * Additional tests for schema components `v1.4.0`_ (2020-12-23) ====================== * Fix for issues #213, #214, #215 and #218 * Code cleaning and optimizations on schema components * Reducing and grouping helper functions `v1.3.1`_ (2020-11-10) ====================== * Apply patches for packaging (issue #210) `v1.3.0`_ (2020-11-09) ====================== * Drop support for Python 3.5 * Add XmlDocument and Wsdl11Document classes * Refactoring of XMLResource to support ElementTree-like XPath API on both full and lazy modes `v1.2.5`_ (2020-09-26) ====================== * Add schema export API to schema and global maps (issue #187) * Fix decoding with lax/skip validation modes (issue #204) * Add *keep_unknown* optional argument for *iter_decode()* methods `v1.2.4`_ (2020-09-13) ====================== * Use the regex engine of *elementpath* library * Fix and extend tests on xs:assert `v1.2.3`_ (2020-08-14) ====================== * Full coverage of W3C tests (excluding ones for unavailable or unimplemented features) * Update and restrict elementpath dependency to v2.0.x * Fix check and iteration of empty model group * Fix substitution group iteration for local elements `v1.2.2`_ (2020-06-15) ====================== * Fix XPath context for schema nodes * Fix XPath parser and context for identities `v1.2.1`_ (2020-06-12) ====================== * Fix content type classification (issue #195) * Make sandbox mode more explicit (PR #191) * Allow alphanumeric prefixes for the base converter * Fix XPath issues with default namespace * Fix W3C tests on XSD identities `v1.2.0`_ (2020-05-28) ====================== * Add ColumnarConverter class * Add command-line interface utility for document API * Fix a stable public API for XSD types, elements and attributes * Add security modes for accessing URLs `v1.1.3`_ (2020-04-28) ====================== * Clean component parsing * Fix namespace loading for chameleon schemas * Fix UPA checks with nested choice/all models * Fixed issues #182 and #183 `v1.1.2`_ (2020-03-22) ====================== * Extension of validation tests with *XMLSchema11* validator * Fixed several bugs * Extended testing with Travis CI `v1.1.1`_ (2020-02-19) ====================== * Change of *skip* validation mode with errors filtering in decode() or encode() * Extension of location hints by argument to imported/included schemas * Fixed lazy validation with identity constraints * Fixed many W3C instance tests (remain ~100 over 15344 tests) `v1.1.0`_ (2020-01-23) ======================= * Removed Python 2 compatibility code * Removed tests code from binary package * Improved identity constraints validation * Added JSON lazy decoding as experimental feature `v1.0.18`_ (2019-12-24) ======================= * Fix for *ModelVisitor.iter_unordered_content()* * Fixed default converter, AbderaConverter and JsonMLConverter for xs:anyType decode * Fixed validation tests with all converters * Added UnorderedConverter to validation tests `v1.0.17`_ (2019-12-22) ======================= * Enhancement of validation-only speed (~15%) * Added *is_valid()* and *iter_errors()* to module API `v1.0.16`_ (2019-11-18) ======================= * Improved XMLResource class for working with compressed files * Fix for validation with XSD wildcards and 'lax' process content * Fix ambiguous items validation for xs:choice and xs:sequence models `v1.0.15`_ (2019-10-13) ======================= * Improved XPath 2.0 bindings * Added logging for schema initialization and building (handled with argument *loglevel*) * Update encoding of collapsed contents with a new model based reordering method * Removed XLink namespace from meta-schema (loaded from a fallback location like XHTML) * Fixed half of failed W3C instance tests (remain 255 over 15344 tests) `v1.0.14`_ (2019-08-27) ======================= * Added XSD 1.1 validator with class *XMLSchema11* * Memory usage optimization with lazy build of the XSD 1.0 and 1.1 meta-schemas * Added facilities for the encoding of unordered and collapsed content `v1.0.13`_ (2019-06-19) ======================= * Fix path normalization and tests for Windows platform * Added XML resource validation in lazy mode (experimental feature) * Added arguments *filler* and *fill_missing* to XSD decode/encode methods * Added arguments *preserve_root*, *strip_namespaces*, *force_dict* and *force_list* to XMLSchemaConverter * Added code coverage and pep8 testing * Drop support for Python 3.4 `v1.0.11`_ (2019-05-05) ======================= * Added a script for running the W3C XSD test suite. * Check restrictions and model groups UPA violations * Model groups splitted between two modules for more focusing on models basics * Added two new exceptions for model group errors * More control on imported namespaces * Added *use_meta* argument to schema classes * Added *includes* list and *imports* dict to schema classes * Many fixes for passing the W3C's tests for XSD 1.0 schemas * Added a test for issue #105 and a fix for issue #103 `v1.0.10`_ (2019-02-25) ======================= * Fixed Element type mismatch issue when apply *SafeXMLParser* to schema resources * More XSD 1.1 features implemented (open content and versioning namespace are missing) `v1.0.9`_ (2019-02-03) ====================== * Programmatic import of ElementTree for avoid module mismatches * Cleaning and refactoring of test scripts `v1.0.8`_ (2019-01-30) ====================== * Dependency *defusedxml* package replaced by a custom XMLParser for ElementTree * Optional decoding of XSD date/time/duration builtin types * Fixes for issues #93, #96, #97 and #99 `v1.0.7`_ (2018-11-15) ====================== * Fixes for issues #87 and #88 * Merged with PR #89 (simpleType restriction annotation parsing) * XSD 1.1 development: added assertion facet (still to be completed) `v1.0.6`_ (2018-10-21) ====================== * Fixes for issues #85 and #86 * XSD 1.1 development: added explicitTimezone facet and XSD 1.1 builtin types `v1.0.5`_ (2018-09-27) ====================== * Fix for issue #82 and for similar unprotected XSD component lookups * Added checks for namespace mapping of encoded trees and error messages `v1.0.4`_ (2018-09-22) ====================== * Unification of XSD group decode and encode methods * Children validation error class improved * Fixes for issues #77, #79 and #80 * Added test scripts for helpers and ElementTree `v1.0.3`_ (2018-08-26) ====================== * Improved model validation for XSD groups encoding * Added parent reference to XSD components * Extended validator errors classes * Optimized error generation using helper methods * Improved particle parsing `v1.0.2`_ (2018-07-26) ====================== * Improved ElementTree and XPath API `v1.0.1`_ (2018-07-14) ====================== * Validated data encoding to XML * Improved converters with decoding/encoding of namespace information * Added helper functions for encoding and decoding to JSON * Added XMLResource class for managing access to XML data sources * Added warnings for failed schema includes and namespace imports `v0.9.31`_ (2018-06-24) ======================= * Schema serialization with pickle for Python 3 (enhancement related to issue #68) * Data encoding with the default converter * Improved decoding for xs:union `v0.9.30`_ (2018-06-06) ======================= * First experimental version of data encoding with the default converter * Fixes for issues #65, #66 and #67 `v0.9.29`_ (2018-06-03) ======================= * Extended the tests on lxml XML data * Fixes for issues #61, #63 and #64 `v0.9.28`_ (2018-05-18) ======================= * Encoding of XSD builtin types (strings and numerical) * Fix for issue #62 * Drop support for Python 3.3 `v0.9.27`_ (2018-05-08) ======================= * Add support for preventing XML attacks with the use of the *defusedxml* package (added *defuse* argument to schemas) * Fix for group circularity (issue #58) * Fix for billion laughs attacks using XSD groups expansion `v0.9.26`_ (2018-04-12) ======================= * Added checks for model restrictions `v0.9.25`_ (2018-04-05) ======================= * Removed XsdAnnotated class * Added XsdType class as common class for XSD types * Fixes for issues #55 and #56 `v0.9.24`_ (2018-04-03) ======================= * Added XPath 1.0/2.0 full parsing with the derived *elementpath* package * Fixes for issues #52 and #54 * Test package improved (tox.ini, other checks with test_package.py) `v0.9.23`_ (2018-03-10) ======================= * Fixes for issues #45, #46, #51 * Added kwargs to *iter_decode()*, *dict_class* and *list_class* arguments have been removed * Added kwargs to converters initialization in order to push variable keyword arguments from *iter_decode()* `v0.9.21`_ (2018-02-15) ======================= * Fixes 'final' derivation attribute for complexType * Decoupling of the XPath module from XsdComponent API * Fix for issue #41 `v0.9.20`_ (2018-01-22) ======================= * Substitution groups support * Added *fetch_schema_locations* function to API * Added *locations* argument to *fetch_schema*, *validate* and *to_dict* API functions * A more useful __repr__ for XSD component classes * Fixes for issues #35, #38, #39 `v0.9.18`_ (2018-01-12) ======================= * Fixed issue #34 (min_occurs == 0 check in XsdGroup.is_emptiable) * Updated copyright information * Updated schema class creation (now use a metaclass) * Added index and expected attributes to XMLSchemaChildrenValidationError * Added *locations* optional argument to XMLSchema class `v0.9.17`_ (2017-12-28) ======================= * Key/Unique/Keyref constraints partially rewritten * Fixed ad issue with UCS-2/4 and maxunicode `v0.9.16`_ (2017-12-23) ======================= * UnicodeSubset class rewritten (more speed, less memory) * Updated unicode_categories.json to Python 3.6 unicodedata * Added XMLSchemaChildrenValidationError exception `v0.9.15`_ (2017-12-15) ======================= * Some bug fixes * Code cleaning * XSD components modules has been merged with schema's modules into 'validators' subpackage `v0.9.14`_ (2017-11-23) ======================= * Improved test scripts with a *SchemaObserver* class and test line arguments * Full support for date and time XSD builtin types `v0.9.12`_ (2017-09-14) ======================= * Added identity constraints * Some bug fix `v0.9.10`_ (2017-07-08) ======================= * Factories code moved to XsdComponent subclasses for simplify parsing and debugging * All XSD components built from ElementTree elements with a lazy approach * Implementation of the XSD validation modes ('strict'/'lax'/'skip') both for validating schemas and for validating/decoding XML files * Defined an XsdBaseComponent class as the common base class for all XSD components, schemas and global maps * Defined a ValidatorMixin for sharing a common API between validators/decoders classes * Added built and validity checks for all XSD components `v0.9.9`_ (2017-06-12) ====================== * Added converters for decode/encode data with different conventions * Modifications on iter_decode() arguments in order to use converters `v0.9.8`_ (2017-05-27) ====================== * Added notations and substitution groups * Created a subpackage for XSD components `v0.9.7`_ (2017-05-21) ====================== * Documentation extended and tested * Improved tests for XPath, validation and decoding v0.9.6 (2017-05-05) =================== * Added an XPath parser * Added iterfind(), find() and findall() APIs for searching XSD element declarations using XPath .. _v0.9.7: https://github.com/brunato/xmlschema/compare/v0.9.6...v0.9.7 .. _v0.9.8: https://github.com/brunato/xmlschema/compare/v0.9.7...v0.9.8 .. _v0.9.9: https://github.com/brunato/xmlschema/compare/v0.9.8...v0.9.9 .. _v0.9.10: https://github.com/brunato/xmlschema/compare/v0.9.9...v0.9.10 .. _v0.9.12: https://github.com/brunato/xmlschema/compare/v0.9.10...v0.9.12 .. _v0.9.14: https://github.com/brunato/xmlschema/compare/v0.9.12...v0.9.14 .. _v0.9.15: https://github.com/brunato/xmlschema/compare/v0.9.14...v0.9.15 .. _v0.9.16: https://github.com/brunato/xmlschema/compare/v0.9.15...v0.9.16 .. _v0.9.17: https://github.com/brunato/xmlschema/compare/v0.9.16...v0.9.17 .. _v0.9.18: https://github.com/brunato/xmlschema/compare/v0.9.17...v0.9.18 .. _v0.9.20: https://github.com/brunato/xmlschema/compare/v0.9.18...v0.9.20 .. _v0.9.21: https://github.com/brunato/xmlschema/compare/v0.9.20...v0.9.21 .. _v0.9.23: https://github.com/brunato/xmlschema/compare/v0.9.21...v0.9.23 .. _v0.9.24: https://github.com/brunato/xmlschema/compare/v0.9.23...v0.9.24 .. _v0.9.25: https://github.com/brunato/xmlschema/compare/v0.9.24...v0.9.25 .. _v0.9.26: https://github.com/brunato/xmlschema/compare/v0.9.25...v0.9.26 .. _v0.9.27: https://github.com/brunato/xmlschema/compare/v0.9.26...v0.9.27 .. _v0.9.28: https://github.com/brunato/xmlschema/compare/v0.9.27...v0.9.28 .. _v0.9.29: https://github.com/brunato/xmlschema/compare/v0.9.28...v0.9.29 .. _v0.9.30: https://github.com/brunato/xmlschema/compare/v0.9.29...v0.9.30 .. _v0.9.31: https://github.com/brunato/xmlschema/compare/v0.9.30...v0.9.31 .. _v1.0.1: https://github.com/brunato/xmlschema/compare/v0.9.31...v1.0.1 .. _v1.0.2: https://github.com/brunato/xmlschema/compare/v1.0.1...v1.0.2 .. _v1.0.3: https://github.com/brunato/xmlschema/compare/v1.0.2...v1.0.3 .. _v1.0.4: https://github.com/brunato/xmlschema/compare/v1.0.3...v1.0.4 .. _v1.0.5: https://github.com/brunato/xmlschema/compare/v1.0.4...v1.0.5 .. _v1.0.6: https://github.com/brunato/xmlschema/compare/v1.0.5...v1.0.6 .. _v1.0.7: https://github.com/brunato/xmlschema/compare/v1.0.6...v1.0.7 .. _v1.0.8: https://github.com/brunato/xmlschema/compare/v1.0.7...v1.0.8 .. _v1.0.9: https://github.com/brunato/xmlschema/compare/v1.0.8...v1.0.9 .. _v1.0.10: https://github.com/brunato/xmlschema/compare/v1.0.9...v1.0.10 .. _v1.0.11: https://github.com/brunato/xmlschema/compare/v1.0.10...v1.0.11 .. _v1.0.13: https://github.com/brunato/xmlschema/compare/v1.0.11...v1.0.13 .. _v1.0.14: https://github.com/brunato/xmlschema/compare/v1.0.13...v1.0.14 .. _v1.0.15: https://github.com/brunato/xmlschema/compare/v1.0.14...v1.0.15 .. _v1.0.16: https://github.com/brunato/xmlschema/compare/v1.0.15...v1.0.16 .. _v1.0.17: https://github.com/brunato/xmlschema/compare/v1.0.16...v1.0.17 .. _v1.0.18: https://github.com/brunato/xmlschema/compare/v1.0.17...v1.0.18 .. _v1.1.0: https://github.com/brunato/xmlschema/compare/v1.0.18...v1.1.0 .. _v1.1.1: https://github.com/brunato/xmlschema/compare/v1.1.0...v1.1.1 .. _v1.1.2: https://github.com/brunato/xmlschema/compare/v1.1.1...v1.1.2 .. _v1.1.3: https://github.com/brunato/xmlschema/compare/v1.1.2...v1.1.3 .. _v1.2.0: https://github.com/brunato/xmlschema/compare/v1.1.3...v1.2.0 .. _v1.2.1: https://github.com/brunato/xmlschema/compare/v1.2.0...v1.2.1 .. _v1.2.2: https://github.com/brunato/xmlschema/compare/v1.2.1...v1.2.2 .. _v1.2.3: https://github.com/brunato/xmlschema/compare/v1.2.2...v1.2.3 .. _v1.2.4: https://github.com/brunato/xmlschema/compare/v1.2.3...v1.2.4 .. _v1.2.5: https://github.com/brunato/xmlschema/compare/v1.2.4...v1.2.5 .. _v1.3.0: https://github.com/brunato/xmlschema/compare/v1.2.5...v1.3.0 .. _v1.3.1: https://github.com/brunato/xmlschema/compare/v1.3.0...v1.3.1 .. _v1.4.0: https://github.com/brunato/xmlschema/compare/v1.3.1...v1.4.0 .. _v1.4.1: https://github.com/brunato/xmlschema/compare/v1.4.0...v1.4.1 .. _v1.4.2: https://github.com/brunato/xmlschema/compare/v1.4.1...v1.4.2 .. _v1.5.0: https://github.com/brunato/xmlschema/compare/v1.4.2...v1.5.0 .. _v1.5.1: https://github.com/brunato/xmlschema/compare/v1.5.0...v1.5.1 .. _v1.5.2: https://github.com/brunato/xmlschema/compare/v1.5.1...v1.5.2 .. _v1.5.3: https://github.com/brunato/xmlschema/compare/v1.5.2...v1.5.3 .. _v1.6.0: https://github.com/brunato/xmlschema/compare/v1.5.3...v1.6.0 .. _v1.6.1: https://github.com/brunato/xmlschema/compare/v1.6.0...v1.6.1 .. _v1.6.2: https://github.com/brunato/xmlschema/compare/v1.6.1...v1.6.2 .. _v1.6.3: https://github.com/brunato/xmlschema/compare/v1.6.2...v1.6.3 .. _v1.6.4: https://github.com/brunato/xmlschema/compare/v1.6.3...v1.6.4 .. _v1.7.0: https://github.com/brunato/xmlschema/compare/v1.6.4...v1.7.0 .. _v1.7.1: https://github.com/brunato/xmlschema/compare/v1.7.0...v1.7.1 .. _v1.8.0: https://github.com/brunato/xmlschema/compare/v1.7.1...v1.8.0 .. _v1.8.1: https://github.com/brunato/xmlschema/compare/v1.8.0...v1.8.1 .. _v1.8.2: https://github.com/brunato/xmlschema/compare/v1.8.1...v1.8.2 .. _v1.9.0: https://github.com/brunato/xmlschema/compare/v1.8.2...v1.9.0 .. _v1.9.1: https://github.com/brunato/xmlschema/compare/v1.9.0...v1.9.1 .. _v1.9.2: https://github.com/brunato/xmlschema/compare/v1.9.1...v1.9.2 .. _v1.10.0: https://github.com/brunato/xmlschema/compare/v1.9.2...v1.10.0 xmlschema-1.10.0/LICENSE000066400000000000000000000021531421140344600145570ustar00rootroot00000000000000The MIT License (MIT) Copyright (c), 2016-2020, SISSA (Scuola Internazionale Superiore di Studi Avanzati) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. xmlschema-1.10.0/MANIFEST.in000066400000000000000000000003761421140344600153150ustar00rootroot00000000000000include MANIFEST.in include LICENSE include README.rst include CHANGELOG.rst include setup.py include setup.cfg include requirements-dev.txt include tox.ini include doc/* recursive-include xmlschema * recursive-include tests * global-exclude *.py[cod] xmlschema-1.10.0/README.rst000066400000000000000000000140541421140344600152440ustar00rootroot00000000000000********* xmlschema ********* .. image:: https://img.shields.io/pypi/v/xmlschema.svg :target: https://pypi.python.org/pypi/xmlschema/ .. image:: https://img.shields.io/pypi/pyversions/xmlschema.svg :target: https://pypi.python.org/pypi/xmlschema/ .. image:: https://img.shields.io/pypi/implementation/xmlschema.svg :target: https://pypi.python.org/pypi/xmlschema/ .. image:: https://img.shields.io/badge/License-MIT-blue.svg :alt: MIT License :target: https://lbesson.mit-license.org/ .. image:: https://img.shields.io/pypi/dm/xmlschema.svg :target: https://pypi.python.org/pypi/xmlschema/ .. image:: https://img.shields.io/badge/Maintained%3F-yes-green.svg :target: https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity .. xmlschema-introduction-start The *xmlschema* library is an implementation of `XML Schema `_ for Python (supports Python 3.7+). This library arises from the needs of a solid Python layer for processing XML Schema based files for `MaX (Materials design at the Exascale) `_ European project. A significant problem is the encoding and the decoding of the XML data files produced by different simulation software. Another important requirement is the XML data validation, in order to put the produced data under control. The lack of a suitable alternative for Python in the schema-based decoding of XML data has led to build this library. Obviously this library can be useful for other cases related to XML Schema based processing, not only for the original scope. The full `xmlschema documentation is available on "Read the Docs" `_. Features ======== This library includes the following features: * Full XSD 1.0 and XSD 1.1 support * Building of XML schema objects from XSD files * Validation of XML instances against XSD schemas * Decoding of XML data into Python data and to JSON * Encoding of Python data and JSON to XML * Data decoding and encoding ruled by converter classes * An XPath based API for finding schema's elements and attributes * Support of XSD validation modes *strict*/*lax*/*skip* * XML attacks protection using an XMLParser that forbids entities * Access control on resources addressed by an URL or filesystem path * XML data bindings based on DataElement class * Static code generation with Jinja2 templates Installation ============ You can install the library with *pip* in a Python 3.6+ environment:: pip install xmlschema The library uses the Python's ElementTree XML library and requires `elementpath `_ additional package. The base schemas of the XSD standards are included in the package for working offline and to speed-up the building of schema instances. .. xmlschema-introduction-end Usage ===== Import the library and then create a schema instance using the path of the file containing the schema as argument: .. code-block:: pycon >>> import xmlschema >>> my_schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') .. note:: For XSD 1.1 schemas use the class `XMLSchema11`, because the default class `XMLSchema` is an alias of the XSD 1.0 validator class `XMLSchema10`. The schema can be used to validate XML documents: .. code-block:: pycon >>> my_schema.is_valid('tests/test_cases/examples/vehicles/vehicles.xml') True >>> my_schema.is_valid('tests/test_cases/examples/vehicles/vehicles-1_error.xml') False >>> my_schema.validate('tests/test_cases/examples/vehicles/vehicles-1_error.xml') Traceback (most recent call last): File "", line 1, in File "/home/brunato/Development/projects/xmlschema/xmlschema/validators/xsdbase.py", line 393, in validate raise error xmlschema.validators.exceptions.XMLSchemaValidationError: failed validating with XsdGroup(model='sequence'). Reason: character data between child elements not allowed! Schema: Instance: NOT ALLOWED CHARACTER DATA Using a schema you can also decode the XML documents to nested dictionaries, with values that match to the data types declared by the schema: .. code-block:: pycon >>> import xmlschema >>> from pprint import pprint >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/collection/collection.xsd') >>> pprint(xs.to_dict('tests/test_cases/examples/collection/collection.xml')) {'@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{'@available': True, '@id': 'b0836217462', 'author': {'@id': 'PAR', 'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter'}, 'estimation': Decimal('10000.00'), 'position': 1, 'title': 'The Umbrellas', 'year': '1886'}, {'@available': True, '@id': 'b0836217463', 'author': {'@id': 'JM', 'born': '1893-04-20', 'dead': '1983-12-25', 'name': 'Joan Miró', 'qualification': 'painter, sculptor and ceramicist'}, 'position': 2, 'title': None, 'year': '1925'}]} Authors ======= Davide Brunato and others who have contributed with code or with sample cases. License ======= This software is distributed under the terms of the MIT License. See the file 'LICENSE' in the root directory of the present distribution, or http://opensource.org/licenses/MIT. xmlschema-1.10.0/doc/000077500000000000000000000000001421140344600143165ustar00rootroot00000000000000xmlschema-1.10.0/doc/Makefile000066400000000000000000000011361421140344600157570ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = xmlschema SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)xmlschema-1.10.0/doc/api.rst000066400000000000000000000256001421140344600156240ustar00rootroot00000000000000.. _package-api: *********** Package API *********** .. _errors-and-exceptions: Errors and exceptions ===================== .. autoexception:: xmlschema.XMLSchemaException .. autoexception:: xmlschema.XMLResourceError .. autoexception:: xmlschema.XMLSchemaNamespaceError .. autoexception:: xmlschema.XMLSchemaValidatorError .. autoexception:: xmlschema.XMLSchemaNotBuiltError .. autoexception:: xmlschema.XMLSchemaParseError .. autoexception:: xmlschema.XMLSchemaModelError .. autoexception:: xmlschema.XMLSchemaModelDepthError .. autoexception:: xmlschema.XMLSchemaValidationError .. autoexception:: xmlschema.XMLSchemaDecodeError .. autoexception:: xmlschema.XMLSchemaEncodeError .. autoexception:: xmlschema.XMLSchemaChildrenValidationError .. autoexception:: xmlschema.XMLSchemaIncludeWarning .. autoexception:: xmlschema.XMLSchemaImportWarning .. autoexception:: xmlschema.XMLSchemaTypeTableWarning .. _document-level-api: Document level API ================== .. autofunction:: xmlschema.validate .. autofunction:: xmlschema.is_valid .. autofunction:: xmlschema.iter_errors .. autofunction:: xmlschema.iter_decode .. autofunction:: xmlschema.to_dict .. autofunction:: xmlschema.to_json .. autofunction:: xmlschema.from_json .. _schema-level-api: Schema level API ================ .. class:: xmlschema.XMLSchema10 .. class:: xmlschema.XMLSchema11 The classes for XSD v1.0 and v1.1 schema instances. They are both generated by the meta-class :class:`XMLSchemaMeta` and take the same API of :class:`XMLSchemaBase`. .. autoclass:: xmlschema.XMLSchema .. autoclass:: xmlschema.XMLSchemaBase .. autoattribute:: root .. automethod:: get_text .. autoattribute:: name .. autoattribute:: url .. autoattribute:: base_url .. autoattribute:: tag .. autoattribute:: id .. autoattribute:: version .. autoattribute:: schema_location .. autoattribute:: no_namespace_schema_location .. autoattribute:: target_prefix .. autoattribute:: default_namespace .. autoattribute:: root_elements .. autoattribute:: simple_types .. autoattribute:: complex_types .. automethod:: builtin_types .. automethod:: create_meta_schema .. automethod:: create_any_content_group .. automethod:: create_any_attribute_group .. automethod:: create_any_type .. automethod:: get_locations .. automethod:: include_schema .. automethod:: import_schema .. automethod:: export .. automethod:: resolve_qname .. automethod:: iter_globals .. automethod:: iter_components .. automethod:: check_schema .. automethod:: build .. automethod:: clear .. autoattribute:: built .. autoattribute:: validation_attempted .. autoattribute:: validity .. autoattribute:: all_errors .. automethod:: get_converter .. automethod:: validate .. automethod:: is_valid .. automethod:: iter_errors .. automethod:: decode .. _schema-iter_decode: .. automethod:: iter_decode .. automethod:: encode .. _schema-iter_encode: .. automethod:: iter_encode .. _global-maps-api: Global maps API =============== .. autoclass:: xmlschema.XsdGlobals :members: copy, register, iter_schemas, iter_globals, lookup_notation, lookup_type, lookup_attribute, lookup_attribute_group, lookup_group, lookup_element, lookup, clear, build, unbuilt, check .. _converters-api: Converters API ============== The base class `XMLSchemaConverter` is used for defining generic converters. The subclasses implement some of the most used `conventions for converting XML to JSON data `_. .. autoclass:: xmlschema.ElementData .. autoclass:: xmlschema.XMLSchemaConverter .. autoattribute:: lossy .. autoattribute:: losslessly .. automethod:: copy .. automethod:: map_attributes .. automethod:: map_content .. automethod:: etree_element .. automethod:: element_decode .. automethod:: element_encode .. automethod:: map_qname .. automethod:: unmap_qname .. autoclass:: xmlschema.UnorderedConverter .. autoclass:: xmlschema.ParkerConverter .. autoclass:: xmlschema.BadgerFishConverter .. autoclass:: xmlschema.AbderaConverter .. autoclass:: xmlschema.JsonMLConverter .. autoclass:: xmlschema.ColumnarConverter .. _data-objects-api: Data objects API ================ .. autoclass:: xmlschema.DataElement .. autoclass:: xmlschema.DataElementConverter .. autoclass:: xmlschema.DataBindingConverter .. _xml-resource-api: XML resources API ================= .. autofunction:: xmlschema.fetch_resource .. autofunction:: xmlschema.fetch_schema .. autofunction:: xmlschema.fetch_schema_locations .. autofunction:: xmlschema.normalize_url .. autoclass:: xmlschema.XMLResource .. autoattribute:: root .. autoattribute:: text .. autoattribute:: name .. autoattribute:: url .. autoattribute:: base_url .. autoattribute:: filepath .. autoattribute:: namespace .. automethod:: parse .. automethod:: tostring .. automethod:: open .. automethod:: load .. automethod:: is_lazy .. autoattribute:: lazy_depth .. automethod:: is_remote .. automethod:: is_local .. automethod:: is_loaded .. automethod:: iter .. automethod:: iter_depth .. automethod:: iterfind .. automethod:: find .. automethod:: findall .. automethod:: iter_location_hints .. automethod:: get_namespaces .. automethod:: get_locations .. autoclass:: xmlschema.XmlDocument .. _xpath-api: XPath API ========= Implemented through a mixin class on XSD schemas and elements. .. autoclass:: xmlschema.ElementPathMixin .. autoattribute:: tag .. autoattribute:: attrib .. automethod:: get .. automethod:: iter .. automethod:: iterchildren .. automethod:: find .. automethod:: findall .. automethod:: iterfind .. _validation-api: Validation API ============== Implemented for XSD schemas, elements, attributes, types, attribute groups and model groups. .. autoclass:: xmlschema.validators.ValidationMixin .. automethod:: is_valid .. automethod:: validate .. automethod:: decode .. automethod:: iter_decode .. automethod:: iter_encode :noindex: .. automethod:: iter_errors .. automethod:: encode .. automethod:: iter_encode .. _particles-api: Particles API ============= Implemented for XSD model groups, elements and element wildcards. .. autoclass:: xmlschema.validators.ParticleMixin .. automethod:: is_empty .. automethod:: is_emptiable .. automethod:: is_single .. automethod:: is_multiple .. automethod:: is_ambiguous .. automethod:: is_univocal .. automethod:: is_missing .. automethod:: is_over .. _main-xsd-components: Main XSD components =================== .. autoclass:: xmlschema.XsdComponent .. autoattribute:: target_namespace .. autoattribute:: local_name .. autoattribute:: qualified_name .. autoattribute:: prefixed_name .. automethod:: is_global .. automethod:: is_matching .. automethod:: tostring .. autoclass:: xmlschema.XsdType :members: is_simple, is_complex, is_atomic, is_list, is_datetime, is_empty, is_emptiable, has_simple_content, has_complex_content, has_mixed_content, is_element_only, is_derived, is_extension, is_restriction, is_key, is_qname .. autoattribute:: simple_type .. autoattribute:: model_group .. autoclass:: xmlschema.XsdElement .. autoclass:: xmlschema.XsdAttribute .. _other-xsd-components: Other XSD components ==================== Elements and attributes ----------------------- .. autoclass:: xmlschema.validators.Xsd11Element .. autoclass:: xmlschema.validators.Xsd11Attribute Types ----- .. autoclass:: xmlschema.validators.Xsd11ComplexType .. autoclass:: xmlschema.validators.XsdComplexType .. autoattribute:: content .. autoclass:: xmlschema.validators.XsdSimpleType .. autoattribute:: enumeration .. autoattribute:: max_value .. autoattribute:: min_value .. autoclass:: xmlschema.validators.XsdAtomicBuiltin .. autoclass:: xmlschema.validators.XsdList .. autoclass:: xmlschema.validators.Xsd11Union .. autoclass:: xmlschema.validators.XsdUnion .. autoclass:: xmlschema.validators.Xsd11AtomicRestriction .. autoclass:: xmlschema.validators.XsdAtomicRestriction Attribute and model groups -------------------------- .. autoclass:: xmlschema.validators.XsdAttributeGroup .. autoclass:: xmlschema.validators.Xsd11Group .. autoclass:: xmlschema.validators.XsdGroup Wildcards --------- .. autoclass:: xmlschema.validators.Xsd11AnyElement .. autoclass:: xmlschema.validators.XsdAnyElement .. autoclass:: xmlschema.validators.Xsd11AnyAttribute .. autoclass:: xmlschema.validators.XsdAnyAttribute .. autoclass:: xmlschema.validators.XsdOpenContent .. autoclass:: xmlschema.validators.XsdDefaultOpenContent Identity constraints -------------------- .. autoclass:: xmlschema.validators.XsdIdentity .. autoclass:: xmlschema.validators.XsdSelector .. autoclass:: xmlschema.validators.XsdFieldSelector .. autoclass:: xmlschema.validators.Xsd11Unique .. autoclass:: xmlschema.validators.XsdUnique .. autoclass:: xmlschema.validators.Xsd11Key .. autoclass:: xmlschema.validators.XsdKey .. autoclass:: xmlschema.validators.Xsd11Keyref .. autoclass:: xmlschema.validators.XsdKeyref Facets ------ .. autoclass:: xmlschema.validators.XsdFacet .. autoclass:: xmlschema.validators.XsdWhiteSpaceFacet .. autoclass:: xmlschema.validators.XsdLengthFacet .. autoclass:: xmlschema.validators.XsdMinLengthFacet .. autoclass:: xmlschema.validators.XsdMaxLengthFacet .. autoclass:: xmlschema.validators.XsdMinInclusiveFacet .. autoclass:: xmlschema.validators.XsdMinExclusiveFacet .. autoclass:: xmlschema.validators.XsdMaxInclusiveFacet .. autoclass:: xmlschema.validators.XsdMaxExclusiveFacet .. autoclass:: xmlschema.validators.XsdTotalDigitsFacet .. autoclass:: xmlschema.validators.XsdFractionDigitsFacet .. autoclass:: xmlschema.validators.XsdExplicitTimezoneFacet .. autoclass:: xmlschema.validators.XsdAssertionFacet .. autoclass:: xmlschema.validators.XsdEnumerationFacets .. autoclass:: xmlschema.validators.XsdPatternFacets Others ------ .. autoclass:: xmlschema.validators.XsdAssert .. autoclass:: xmlschema.validators.XsdAlternative .. autoclass:: xmlschema.validators.XsdNotation .. autoclass:: xmlschema.validators.XsdAnnotation .. _extra-api: Extra features API ================== Code generators --------------- .. autoclass:: xmlschema.extras.codegen.AbstractGenerator .. automethod:: map_type .. automethod:: list_templates .. automethod:: matching_templates .. automethod:: get_template .. automethod:: select_template .. automethod:: render .. automethod:: render_to_files .. autoclass:: xmlschema.extras.codegen.PythonGenerator WSDL 1.1 documents ------------------ .. autoclass:: xmlschema.extras.wsdl.Wsdl11Document .. autoattribute:: messages .. autoattribute:: port_types .. autoattribute:: bindings .. autoattribute:: services xmlschema-1.10.0/doc/components.rst000066400000000000000000000260111421140344600172350ustar00rootroot00000000000000.. _schema-components: ***************** Schema components ***************** After the building a schema object contains a set of components that represent the definitions/declarations defined in loaded schema files. These components, sometimes referred as *Post Schema Validation Infoset* or **PSVI**, constitute an augmentation of the original information contained into schema files. .. testsetup:: collection import xmlschema import os import warnings if os.getcwd().endswith('/doc'): os.chdir('..') warnings.simplefilter("ignore", xmlschema.XMLSchemaIncludeWarning) schema = xmlschema.XMLSchema('tests/test_cases/examples/collection/collection.xsd') Accessing schema components =========================== Taking the *collection.xsd* as sample schema to illustrate the access to components, we can iterate the entire set of components, globals an locals, using the *iter_components()* generator function: .. doctest:: collection >>> import xmlschema >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/collection/collection.xsd') >>> for xsd_component in schema.iter_components(): ... xsd_component ... XMLSchema10(name='collection.xsd', namespace='http://example.com/ns/collection') XsdComplexType(name='personType') XsdAttributeGroup(['id']) XsdAttribute(name='id') XsdGroup(model='sequence', occurs=[1, 1]) XsdElement(name='name', occurs=[1, 1]) ... ... XsdElement(name='object', occurs=[1, None]) XsdElement(name='person', occurs=[1, 1]) For taking only global components use *iter_globals()* instead: .. doctest:: collection >>> for xsd_component in schema.iter_globals(): ... xsd_component ... XsdComplexType(name='personType') XsdComplexType(name='objType') XsdElement(name='collection', occurs=[1, 1]) XsdElement(name='person', occurs=[1, 1]) Access with XPath API --------------------- Another method for retrieving XSD elements and attributes of a schema is to use XPath expressions with *find* or *findall* methods: .. doctest:: collection >>> from pprint import pprint >>> namespaces = {'': 'http://example.com/ns/collection'} >>> schema.find('collection/object', namespaces) XsdElement(name='object', occurs=[1, None]) >>> pprint(schema.findall('collection/object/*', namespaces)) [XsdElement(name='position', occurs=[1, 1]), XsdElement(name='title', occurs=[1, 1]), XsdElement(name='year', occurs=[1, 1]), XsdElement(name='author', occurs=[1, 1]), XsdElement(name='estimation', occurs=[0, 1]), XsdElement(name='characters', occurs=[0, 1])] Access to global components --------------------------- Accessing a specific type of global component a dictionary access may be preferred: .. doctest:: collection >>> schema.elements['person'] XsdElement(name='person', occurs=[1, 1]) >>> schema.types['personType'] XsdComplexType(name='personType') The schema object has a dictionary attribute for each type of XSD declarations (*elements*, *attributes* and *notations*) and for each type of XSD definitions (*types*, *model groups*, *attribute groups*, *identity constraints* and *substitution groups*). These dictionaries are only views of common dictionaries, shared by all the loaded schemas in a structure called *maps*: .. doctest:: collection >>> schema.maps XsdGlobals(validator=XMLSchema10(name='collection.xsd', ...) .. doctest:: collection >>> person = schema.elements['person'] >>> person XsdElement(name='person', occurs=[1, 1]) >>> schema.maps.elements[person.qualified_name] XsdElement(name='person', occurs=[1, 1]) Component structure =================== Only the main component classes are available at package level: XsdComponent The base class of every XSD component. XsdType The base class of every XSD type, both complex and simple types. XsdElement The XSD 1.0 element class, base also of XSD 1.1 element class. XsdAttribute The XSD 1.0 attribute class, base also of XSD 1.1 attribute class. The full schema components are provided only by accessing the `xmlschema.validators` subpackage, for example: .. doctest:: >>> import xmlschema >>> xmlschema.validators.Xsd11Element Connection with the schema -------------------------- Every component is linked to its container schema and a reference node of its XSD schema document: .. doctest:: collection >>> person = schema.elements['person'] >>> person.schema XMLSchema10(name='collection.xsd', namespace='http://example.com/ns/collection') >>> person.elem >>> person.tostring() '' Naming options -------------- A component that has a name (eg. elements or global types) can be referenced with a different name format, so there are some properties for getting these formats: .. doctest:: collection >>> vh_schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> car = vh_schema.find('vh:vehicles/vh:cars/vh:car') >>> car.name '{http://example.com/vehicles}car' >>> car.local_name 'car' >>> car.prefixed_name 'vh:car' >>> car.qualified_name '{http://example.com/vehicles}car' >>> car.attributes['model'].name 'model' >>> car.attributes['model'].qualified_name '{http://example.com/vehicles}model' Decoding and encoding --------------------- Every schema component includes methods for data conversion: .. doctest:: >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema.types['vehicleType'].decode >>> schema.elements['cars'].encode Those methods can be used to decode the correspondents parts of the XML document: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> from xml.etree import ElementTree >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> xt = ElementTree.parse('tests/test_cases/examples/vehicles/vehicles.xml') >>> root = xt.getroot() >>> pprint(xs.elements['cars'].decode(root[0])) {'{http://example.com/vehicles}car': [{'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'}]} >>> pprint(xs.elements['cars'].decode(xt.getroot()[1], validation='skip')) None >>> pprint(xs.elements['bikes'].decode(root[1], namespaces={'vh': 'http://example.com/vehicles'})) {'@xmlns:vh': 'http://example.com/vehicles', 'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]} XSD types ========= Every element or attribute declaration has a *type* attribute for accessing its XSD type: .. doctest:: collection >>> person = schema.elements['person'] >>> person.type XsdComplexType(name='personType') Simple types ------------ Simple types are used on attributes and elements that contains a text value: .. doctest:: >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema.attributes['step'] XsdAttribute(name='vh:step') >>> schema.attributes['step'].type XsdAtomicBuiltin(name='xs:positiveInteger') A simple type doesn't have attributes but can have facets-related validators or properties: .. doctest:: >>> schema.attributes['step'].type.attributes Traceback (most recent call last): File "", line 1, in AttributeError: 'XsdAtomicBuiltin' object has no attribute 'attributes' >>> schema.attributes['step'].type.validators [] >>> schema.attributes['step'].type.white_space 'collapse' To check if a type is a simpleType use *is_simple()*: .. doctest:: >>> schema.attributes['step'].type.is_simple() True Complex types ------------- Complex types are used only for elements with attributes or with child elements. For accessing the attributes there is always defined and attribute group, also when the complex type has no attributes: .. doctest:: collection >>> schema.types['objType'] XsdComplexType(name='objType') >>> schema.types['objType'].attributes XsdAttributeGroup(['id', 'available']) >>> schema.types['objType'].attributes['available'] XsdAttribute(name='available') For accessing the content model there use the attribute *content*. In most cases the element's type is a complexType with a complex content and in these cases *content* is a not-empty `XsdGroup`: .. doctest:: collection >>> person = schema.elements['person'] >>> person.type.has_complex_content() True >>> person.type.content XsdGroup(model='sequence', occurs=[1, 1]) >>> for item in person.type.content: ... item ... XsdElement(name='name', occurs=[1, 1]) XsdElement(name='born', occurs=[1, 1]) XsdElement(name='dead', occurs=[0, 1]) XsdElement(name='qualification', occurs=[0, 1]) .. note:: The attribute *content_type* has been renamed to *content* in v1.2.1 in order to avoid confusions between the complex type and its content. A property with the old name will be maintained until v2.0. Model groups can be nested with very complex structures, so there is an generator function *iter_elements()* to traverse a model group: .. doctest:: collection >>> for e in person.type.content.iter_elements(): ... e ... XsdElement(name='name', occurs=[1, 1]) XsdElement(name='born', occurs=[1, 1]) XsdElement(name='dead', occurs=[0, 1]) XsdElement(name='qualification', occurs=[0, 1]) Sometimes a complex type can have a simple content, in these cases *content* is a simple type. Content types ------------- An element can have four different content types: - **empty**: deny child elements, deny text content - **simple**: deny child elements, allow text content - **element-only**: allow child elements, deny intermingled text content - **mixed**: allow child elements and intermingled text content For attributes only *empty* or *simple* content types are possible, because they can have only a simpleType value. The reference methods for checking the content type are respectively *is_empty()*, *has_simple_content()*, *is_element_only()* and *has_mixed_content()*. Access to content validator --------------------------- The content type checking can be complicated if you want to know which is the content validator without use a type checking. To making this simpler there are two properties defined for XSD types: simple_type a simple type in case of *simple* content or when an *empty* content is based on an empty simple type, `None` otherwise. model_group a model group in case of *mixed* or *element-only* content or when an *empty* content is based on an empty model group, `None` otherwise. xmlschema-1.10.0/doc/conf.py000066400000000000000000000113711421140344600156200ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # xmlschema documentation build configuration file, created by # sphinx-quickstart on Fri Jan 12 09:05:46 2018. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # Extends the path with parent directory in order to # import xmlschema from the project also if it's installed. import sys import os sys.path.insert(0, os.path.abspath('..')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] # Option for autodoc: do not add module name as prefix to classes or functions. add_module_names = False # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = 'xmlschema' copyright = '2016-2021, SISSA - Scuola Internazionale Superiore di Studi Avanzati' author = 'Davide Brunato' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.10' # The full version, including alpha/beta/rc tags. release = '1.10.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # html_theme = 'alabaster' html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', ] } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'xmlschemadoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'xmlschema.tex', 'xmlschema Documentation', 'Davide Brunato', 'manual'), ] latex_appendices = ['api'] xmlschema-1.10.0/doc/converters.rst000066400000000000000000000124261421140344600172470ustar00rootroot00000000000000.. _converters: *********************** Converters for XML data *********************** XML data decoding and encoding is handled using an intermediate converter class instance that takes charge of composing inner data and mapping of namespaces and prefixes. Because XML is a structured format that includes data and metadata information, as attributes and namespace declarations, is necessary to define conventions for naming the different data objects in a distinguishable way. For example a wide-used convention is to prefixing attribute names with an '@' character. With this convention the attribute `name='John'` is decoded to `'@name': 'John'`, or `'level='10'` is decoded to `'@level': 10`. A related topic is the mapping of namespaces. The expanded namespace representation is used within XML objects of the ElementTree library. For example `{http://www.w3.org/2001/XMLSchema}string` is the fully qualified name of the XSD string type, usually referred as *xs:string* or *xsd:string* with a namespace declaration. With string serialization of XML data the names are remapped to prefixed format. This mapping is generally useful also if you serialize XML data to another format like JSON, because prefixed name is more manageable and readable than expanded format. Available converters ==================== The library includes some converters. The default converter :class:`XMLSchemaConverter` is the base class of other converter types. Each derived converter type implements a well know convention, related to the conversion from XML to JSON data format: * :class:`ParkerConverter`: `Parker convention `_ * :class:`BadgerFishConverter`: `BadgerFish convention `_ * :class:`AbderaConverter`: `Apache Abdera project convention `_ * :class:`JsonMLConverter`: `JsonML (JSON Mark-up Language) convention `_ A summary of these and other conventions can be found on the wiki page `JSON and XML Conversion `_. The base class, that not implements any particular convention, has several options that can be used to variate the converting process. Some of these options are not used by other predefined converter types (eg. *force_list* and *force_dict*) or are used with a fixed value (eg. *text_key* or *attr_prefix*). See :ref:`converters-api` for details about base class options and attributes. Moreover there are also other two converters useful for specific cases: * :class:`UnorderedConverter`: like default converter but with unordered decoding and encoding. * :class:`ColumnarConverter`: a converter that remaps attributes as child elements in a columnar shape (available since release v1.2.0). * :class:`DataElementConverter`: a converter that converts XML to a tree of :class:`DataElement` intances, Element-like objects with decoded values and schema bindings (available since release v1.5.0). Create a custom converter ========================= To create a new customized converter you have to subclass the :class:`XMLSchemaConverter` and redefine the two methods *element_decode* and *element_encode*. These methods are based on the namedtuple `ElementData`, an Element-like data structure that stores the decoded Element parts. This namedtuple is used by decoding and encoding methods as an intermediate data structure. The namedtuple `ElementData` has four attributes: * **tag**: the element's tag string; * **text**: the element's text, that can be a string or `None` for empty elements; * **content**: the element's children, can be a list or `None`; * **attributes**: the element's attributes, can be a dictionary or `None`. The method *element_decode* receives as first argument an `ElementData` instance with decoded data. The other arguments are the XSD element to use for decoding and the level of the XML decoding process, used to add indent spaces for a readable string serialization. This method uses the input data element to compose a decoded data, typically a dictionary or a list or a value for simple type elements. On the opposite the method *element_encode* receives the decoded object and decompose it in order to get and returns an `ElementData` instance. This instance has to contain the parts of the element that will be then encoded an used to build an XML Element instance. These two methods have also the responsibility to map and unmap object names, but don't have to decode or encode data, a task that is delegated to the methods of the XSD components. Depending on the format defined by your new converter class you may provide a different value for properties *lossless* and *losslessly*. The *lossless* has to be `True` if your new converter class preserves all XML data information (eg. as the *BadgerFish* convention). Your new converter can be also *losslessly* if it's lossless and the element model structure and order is maintained (like the JsonML convention). Furthermore your new converter class can has a more specific `__init__` method in order to avoid the usage of unused options or to set the value of some other options. Finally refer also to the code of predefined derived converters to see how you can build your own one. xmlschema-1.10.0/doc/extras.rst000066400000000000000000000077471421140344600163750ustar00rootroot00000000000000************** Extra features ************** The subpackage *xmlschema.extras* acts as a container of a set of extra modules or subpackages that can be useful for specific needs. These codes are not imported during normal library usage and may require additional dependencies to be installed. This choice should be facilitate the implementation of other optional functionalities without having an impact on the base configuration. .. testsetup:: import xmlschema import os import warnings if os.getcwd().endswith('/doc'): os.chdir('..') warnings.simplefilter("ignore", xmlschema.XMLSchemaIncludeWarning) .. _code-generators: Code generation with Jinja2 templates ===================================== The module *xmlschema.extras.codegen* provides an abstract base class :class:`AbstractGenerator` for generate source code from parsed XSD schemas. The Jinja2 engine is embedded in that class and empowered with a set of custom filters and tests for accessing to defined XSD schema components. Schema based filters -------------------- Within templates you can use a set of addional filters, available for all generator subclasses: name Get the unqualified name of the object. Invalid chars for identifiers are replaced by an underscore. qname Get the QName of the object in prefixed form. Invalid chars for identifiers are replaced by an underscore. namespace Get the namespace URI of the XSD component. type_name Get the unqualified name of an XSD type. For default 'Type' or '_type' suffixes are removed. Invalid chars for identifiers are replaced by an underscore. type_qname Get the QName of an XSD type in prefixed form. For default 'Type' or '_type' suffixes are removed. Invalid chars for identifiers are replaced by an underscore. sort_types Sort a sequence or a map of XSD types, in reverse dependency order, detecting circularities. Type mapping ------------ Each implementation of a generator class has an additional filter for translating types using the types map of the instance. For example a :class:`PythonGenerator` has the filter *python_type*. These filters are based on a common method *map_type* that uses an instance dictionary built at initialization time from a class maps for builtin types and an optional initialization argument for the types defined in the schema. Defining additional Jinja2 filters and tests -------------------------------------------- Defining a generator class you can add filters and tests using *filter_method* and *test_method* decorators: .. doctest:: >>> from xmlschema.extras.codegen import AbstractGenerator, filter_method, test_method >>> >>> class DemoGenerator(AbstractGenerator): ... formal_language = 'Demo' ... ... @filter_method ... def my_filter_method(self, obj): ... """A method that filters an object using the schema.""" ... ... @staticmethod ... @test_method ... def my_test_method(obj): ... """A static method that test an object.""" ... .. _wsdl11-documents: WSDL 1.1 documents ================== The module *xmlschema.extras.wsdl* provides a specialized schema-related XML document for WSDL 1.1. An example of specialization is the class :class:`Wsdl11Document`, usable for validating and parsing WSDL 1.1 documents, that can be imported from *wsdl* module of the *extra* subpackage: .. doctest:: >>> from xmlschema.extras.wsdl import Wsdl11Document >>> wsdl_document = Wsdl11Document('tests/test_cases/examples/stockquote/stockquoteservice.wsdl') >>> wsdl_document.schema XMLSchema10(name='wsdl.xsd', namespace='http://schemas.xmlsoap.org/wsdl/') A parsed WSDL 1.1 document can aggregate a set of WSDL/XSD files for building interrelated set of definitions in multiple namespaces. The XMLResource base class and schema validation assure a fully checked WSDL document with protections against XML attacks. See :class:`xmlschema.extras.wsdl.Wsdl11Document` API for details. xmlschema-1.10.0/doc/features.rst000066400000000000000000000146751421140344600167030ustar00rootroot00000000000000************** Other features ************** Schema objects and package APIs include a set of other features that have been added since a specific release. These features are regulated by arguments, alternative classes or module parameters. XSD 1.0 and 1.1 support ======================= From release v1.0.14 XSD 1.1 support has been added to the library through the class :class:`XMLSchema11`. You have to use this class for XSD 1.1 schemas instead the default class :class:`XMLSchema`, that is linked to XSD 1.0 validator :class:`XMLSchema10`. The XSD 1.1 validator can be used also for validating XSD 1.0 schemas, except for a restricted set of cases related to content extension in a complexType (the extension of a complex content with simple base is allowed in XSD 1.0 and forbidden in XSD 1.1). CLI interface ============= Starting from the version v1.2.0 the package has a CLI interface with three console scripts: xmlschema-validate Validate a set of XML files. xmlschema-xml2json Decode a set of XML files to JSON. xmlschema-json2xml Encode a set of JSON files to XML. XSD validation modes ==================== Since the version v0.9.10 the library uses XSD validation modes *strict*/*lax*/*skip*, both for schemas and for XML instances. Each validation mode defines a specific behaviour: strict Schemas are validated against the meta-schema. The processor stops when an error is found in a schema or during the validation/decode of XML data. lax Schemas are validated against the meta-schema. The processor collects the errors and continues, eventually replacing missing parts with wildcards. Undecodable XML data are replaced with `None`. skip Schemas are not validated against the meta-schema. The processor doesn't collect any error. Undecodable XML data are replaced with the original text. The default mode is *strict*, both for schemas and for XML data. The mode is set with the *validation* argument, provided when creating the schema instance or when you want to validate/decode XML data. For example you can build a schema using a *strict* mode and then decode XML data using the *validation* argument setted to 'lax'. .. note:: From release v1.1.1 the *iter_decode()* and *iter_encode()* methods propagate errors also for *skip* validation mode. The errors generated in *skip* mode are discarded by the top-level methods *decode()* and *encode()*. Lazy validation =============== From release v1.0.12 the document validation and the decoding API have an optional argument `lazy=False`, that can be changed to `True` for operating with a lazy :class:`XMLResource`. The lazy mode can be useful for validating and decoding big XML data files, consuming less memory. From release v1.1.0 the *lazy* mode can be also set with a non negative integer. A zero is equivalent to `False`, a positive value means that lazy mode is activated and defines also the *lazy depth* to use for traversing the XML data tree. Lazy mode works better with validation because is not needed to use converters for shaping decoded data. XML entity-based attacks protection =================================== The XML data resource loading is protected using the `SafeXMLParser` class, a subclass of the pure Python version of XMLParser that forbids the use of entities. The protection is applied both to XSD schemas and to XML data. The usage of this feature is regulated by the XMLSchema's argument *defuse*. For default this argument has value *'remote'* that means the protection on XML data is applied only to data loaded from remote. Providing *'nonlocal'* all XML data are defused except local files. Other values for this argument can be *'always'* and *'never'*, with obvious meaning. Access control on accessing resources ===================================== From release v1.2.0 the schema class includes an argument named *allow* for protecting the access to XML resources identified by an URL or filesystem path. For default all types of URLs are allowed. Provide a different value to restrict the set of URLs that the schema instance can access: all All types of URL and file paths are allowed. remote Only remote resource URLs are allowed. local Only file paths and file-related URLs are allowed. sandbox Allows only the file paths and URLs that are under the directory path identified by *source* argument or *base_url* argument. none No URL based or file path access is allowed. .. warning:: For protecting services that are freely accessible for validation (eg. a web on-line validator that has a form for loading schema and/or XML instance) the recommendation is to provide 'always' for the *defuse* argument and 'none' for the *allow* argument. These settings prevent attacks to your local filesystem, through direct paths or injection in XSD schema imports or includes. For XSD schemas, if you want to permit imports of namespaces located on other web services you can provide 'remote' for the *allow* argument and provide an `XMLResource` instance, initialized providing `allow='none'`, as the *source* argument for the main schema. Processing limits ================= From release v1.0.16 a module has been added in order to group constants that define processing limits, generally to protect against attacks prepared to exhaust system resources. These limits usually don't need to be changed, but this possibility has been left at the module level for situations where a different setting is needed. Limit on XSD model groups checking ---------------------------------- Model groups of the schemas are checked against restriction violations and *Unique Particle Attribution* violations. To avoids XSD model recursion attacks a depth limit of 15 levels is set. If this limit is exceeded an ``XMLSchemaModelDepthError`` is raised, the error is caught and a warning is generated. If you need to set an higher limit for checking all your groups you can import the library and change the value of ``MAX_MODEL_DEPTH`` in the limits module: .. doctest:: >>> import xmlschema >>> xmlschema.limits.MAX_MODEL_DEPTH = 20 Limit on XML data depth ----------------------- A limit of 9999 on maximum depth is set for XML validation/decoding/encoding to avoid attacks based on extremely deep XML data. To increase or decrease this limit change the value of ``MAX_XML_DEPTH`` in the module *limits* after the import of the package: .. doctest:: >>> import xmlschema >>> xmlschema.limits.MAX_XML_DEPTH = 1000 xmlschema-1.10.0/doc/index.rst000066400000000000000000000003261421140344600161600ustar00rootroot00000000000000xmlschema Documentation ======================= .. toctree:: :maxdepth: 2 intro usage features converters components testing extras .. only:: html .. toctree:: api xmlschema-1.10.0/doc/intro.rst000066400000000000000000000007241421140344600162060ustar00rootroot00000000000000************ Introduction ************ .. include:: ../README.rst :start-after: xmlschema-introduction-start :end-before: xmlschema-introduction-end License ======= The *xmlschema* library is distributed under the terms of the `MIT License `_. Support ======= This software is hosted on GitHub, refer to the `xmlschema's project page `_ for source code and for an issue tracker. xmlschema-1.10.0/doc/testing.rst000066400000000000000000000134411421140344600165300ustar00rootroot00000000000000******* Testing ******* The tests of the *xmlschema* library are implemented using the Python's *unitest* library. From version v1.1.0 the test scripts have been moved into the directory ``tests/`` of the source distribution. Only a small subpackage *extras/testing/*, containing a specialized UnitTest subclass, a factory and builders for creating test classes for XSD and XML file, has been left into the package's code. Test scripts ============ There are several test scripts, each one for a different target. These scripts can be run individually or by the unittest module. For example to run XPath tests through the *unittest* module use the command: .. code-block:: bash $ python -m unittest -k tests.test_xpath .......... ---------------------------------------------------------------------- Ran 10 tests in 0.133s OK The same run can be launched with the command `$ python tests/test_xpath.py` but an additional header, containing info about the package location, the Python version and the machine platform, is displayed before running the tests. Under the base directory *tests/* there are the test scripts for the base modules of the package. The subdirectory *tests/validators* includes tests for XSD validators building (schemas and their components) and the subdirectory *tests/validation* contains tests validation of XSD/XML and decoding/encoding of XML files. To run all tests use the command `python -m unittest `. Also, the script *test_all.py* can launched during development to run all the tests except memory and packaging tests. From the project source base, if you have the *tox automation tool* installed, you can run all tests with all supported Python's versions using the command ``tox``. Test cases based on files ========================= Three scripts (*test_all.py*, *test_schemas.py*, *test_validation.py*) create many tests dinamically, building test classes from a set of XSD/XML files. Only a small set of test files is published in the repository for copyright reasons. You can find the repository test files into ``tests/test_cases/`` subdirectory. You can locally extend the test with your set of files. For doing this create a submodule or a directory outside the repository directory and then copy your XSD/XML files into it. Create an index file called testfiles into the base directory were you put your cases and fill it with the list of paths of files you want to be tested, one per line, as in the following example: .. code-block:: text # XHTML XHTML/xhtml11-mod.xsd XHTML/xhtml-datatypes-1.xsd # Quantum Espresso qe/qes.xsd qe/qes_neb.xsd qe/qes_with_choice_no_nesting.xsd qe/silicon.xml qe/silicon-1_error.xml --errors 1 qe/silicon-3_errors.xml --errors=3 qe/SrTiO_3.xml qe/SrTiO_3-2_errors.xml --errors 2 The test scripts create a test for each listed file, dependant from the context. For example the script *test_schemas.py* uses only *.xsd* files, where instead the script *tests_validation.py* uses only *.xml* files. If a file has errors insert an integer number after the path. This is the number of errors that the XML Schema validator have to found to pass the test. From version 1.0.0 each test-case line is parsed for those additional arguments: **-L URI URL** Schema location hint overrides. **--version=VERSION** XSD schema version to use for the test case (default is 1.0). **--errors=NUM** Number of errors expected (default=0). **--warnings=NUM** Number of warnings expected (default=0). **--inspect** Inspect using an observed custom schema class. **--defuse=(always, remote, never)** Define when to use the defused XML data loaders. **--timeout=SEC** Timeout for fetching resources (default=300). **--lax-encode** Use lax mode on encode checks (for cases where test data uses default or fixed values or some test data are skipped by wildcards processContents). Ignored on schema tests. **--debug** Activate the debug mode (only the cases with `--debug` are executed). **--codegen** Test code generation with XML data bindings module. If you put a ``--help`` on the first case line the argument parser show you all the options available. To run tests with also your personal set of files you have provide the path to your custom *testfile*, index, for example: .. code-block:: text python xmlschema/tests/test_all.py ../extra-schemas/testfiles Testing with the W3C XML Schema 1.1 test suite ============================================== From release v1.0.11, using the script *test_w3c_suite.py*, you can run also tests based on the `W3C XML Schema 1.1 test suite `_. To run these tests clone the W3C repo on the project's parent directory and than run the script: .. code-block:: text git clone https://github.com/w3c/xsdtests.git python xmlschema/xmlschema/tests/test_w3c_suite.py You can also provides additional options for select a subset of W3C tests, run ``test_w3_suite.py --help`` to show available options. Direct testing of schemas and instances ======================================= From release v1.0.12, using the script *test_files.py*, you can test schemas or XML instances passing them as arguments: .. code-block:: text $ cd tests/ $ python test_files.py test_cases/examples/vehicles/*.xsd Add test 'TestSchema001' for file 'test_cases/examples/vehicles/bikes.xsd' ... Add test 'TestSchema002' for file 'test_cases/examples/vehicles/cars.xsd' ... Add test 'TestSchema003' for file 'test_cases/examples/vehicles/types.xsd' ... Add test 'TestSchema004' for file 'test_cases/examples/vehicles/vehicles-max.xsd' ... Add test 'TestSchema005' for file 'test_cases/examples/vehicles/vehicles.xsd' ... ..... ---------------------------------------------------------------------- Ran 5 tests in 0.147s OK xmlschema-1.10.0/doc/usage.rst000066400000000000000000000506511421140344600161630ustar00rootroot00000000000000***** Usage ***** .. _lxml: http://lxml.de .. testsetup:: import xmlschema import os import warnings if os.getcwd().endswith('/doc'): os.chdir('..') warnings.simplefilter("ignore", xmlschema.XMLSchemaIncludeWarning) .. testsetup:: collection import xmlschema import os import warnings if os.getcwd().endswith('/doc'): os.chdir('..') warnings.simplefilter("ignore", xmlschema.XMLSchemaIncludeWarning) schema = xmlschema.XMLSchema('tests/test_cases/examples/collection/collection.xsd') Create a schema instance ======================== Import the library and then create an instance of a schema using the path of the file containing the schema as argument: .. doctest:: >>> import xmlschema >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') The argument can be also a file-like object or a string containing the schema definition: .. doctest:: >>> schema_file = open('tests/test_cases/examples/collection/collection.xsd') >>> schema = xmlschema.XMLSchema(schema_file) .. doctest:: >>> schema = xmlschema.XMLSchema(""" ... ... ... ... """) Strings and file-like objects might not work when the schema includes other local subschemas, because the package cannot knows anything about the schema's source location: .. doctest:: >>> schema_xsd = open('tests/test_cases/examples/vehicles/vehicles.xsd').read() >>> schema = xmlschema.XMLSchema(schema_xsd) Traceback (most recent call last): ... ... xmlschema.validators.exceptions.XMLSchemaParseError: unknown element '{http://example.com/vehicles}cars': Schema: Path: /xs:schema/xs:element/xs:complexType/xs:sequence/xs:element In these cases you can provide an appropriate *base_url* optional argument to define the reference directory path for other includes and imports: .. doctest:: >>> schema_file = open('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema = xmlschema.XMLSchema(schema_file, base_url='tests/test_cases/examples/vehicles/') Non standard options for schema instance creation ------------------------------------------------- Other options for schema instance creation are available using non-standard methods. Most cases require to use the *build* option to delay the schema build after the loading of all schema resources. For example: .. doctest:: >>> schema_file = open('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema = xmlschema.XMLSchema(schema_file, build=False) >>> _ = schema.include_schema('tests/test_cases/examples/vehicles/cars.xsd') >>> _ = schema.include_schema('tests/test_cases/examples/vehicles/bikes.xsd') >>> schema.build() Another option, available from release v1.6.1, is to provide a list of schema sources, particurlaly useful when sources have no locations associated: .. doctest:: >>> sources = [open('tests/test_cases/examples/vehicles/vehicles.xsd'), ... open('tests/test_cases/examples/vehicles/cars.xsd'), ... open('tests/test_cases/examples/vehicles/bikes.xsd'), ... open('tests/test_cases/examples/vehicles/types.xsd')] >>> schema = xmlschema.XMLSchema(sources) or similarly to the previous example one can use the method :meth:`add_schema()`: .. doctest:: >>> schema_file = open('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema = xmlschema.XMLSchema(schema_file, build=False) >>> _ = schema.add_schema(open('tests/test_cases/examples/vehicles/cars.xsd')) >>> _ = schema.add_schema(open('tests/test_cases/examples/vehicles/bikes.xsd')) >>> _ = schema.add_schema(open('tests/test_cases/examples/vehicles/types.xsd')) >>> schema.build() .. note:: Anyway the advice is to build intermediate XSD schemas intead for loading all the schemas needed in a standard way, because XSD mechanisms of imports, includes, redefines and overrides are usually supported when you submit your schemas to other XSD validators. Validation ========== A schema instance has methods to validate an XML document against the schema. The first method is :meth:`XMLSchema.is_valid`, that returns ``True`` if the XML argument is validated by the schema loaded in the instance, and returns ``False`` if the document is invalid. .. doctest:: >>> import xmlschema >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema.is_valid('tests/test_cases/examples/vehicles/vehicles.xml') True >>> schema.is_valid('tests/test_cases/examples/vehicles/vehicles-1_error.xml') False >>> schema.is_valid("""""") False An alternative mode for validating an XML document is implemented by the method :meth:`XMLSchema.validate`, that raises an error when the XML doesn't conforms to the schema: .. doctest:: >>> import xmlschema >>> schema = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> schema.validate('tests/test_cases/examples/vehicles/vehicles.xml') >>> schema.validate('tests/test_cases/examples/vehicles/vehicles-1_error.xml') Traceback (most recent call last): File "", line 1, in File "/home/brunato/Development/projects/xmlschema/xmlschema/schema.py", line 220, in validate raise error xmlschema.exceptions.XMLSchemaValidationError: failed validating Instance: NOT ALLOWED CHARACTER DATA A validation method is also available at module level, useful when you need to validate a document only once or if you extract information about the schema, typically the schema location and the namespace, directly from the XML document: .. doctest:: >>> xmlschema.validate('tests/test_cases/examples/vehicles/vehicles.xml') >>> xml_file = 'tests/test_cases/examples/vehicles/vehicles.xml' >>> xsd_file = 'tests/test_cases/examples/vehicles/vehicles.xsd' >>> xmlschema.validate(xml_file, schema=xsd_file) Data decoding and encoding ========================== A schema instance can be also used for decoding an XML document to a nested dictionary: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> pprint(xs.to_dict('tests/test_cases/examples/vehicles/vehicles.xml')) {'@xmlns:vh': 'http://example.com/vehicles', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd', 'vh:bikes': {'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]}, 'vh:cars': {'vh:car': [{'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'}]}} The decoded values match the datatypes declared in the XSD schema: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/collection/collection.xsd') >>> pprint(xs.to_dict('tests/test_cases/examples/collection/collection.xml')) {'@xmlns:col': 'http://example.com/ns/collection', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{'@available': True, '@id': 'b0836217462', 'author': {'@id': 'PAR', 'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter'}, 'estimation': Decimal('10000.00'), 'position': 1, 'title': 'The Umbrellas', 'year': '1886'}, {'@available': True, '@id': 'b0836217463', 'author': {'@id': 'JM', 'born': '1893-04-20', 'dead': '1983-12-25', 'name': 'Joan Miró', 'qualification': 'painter, sculptor and ceramicist'}, 'position': 2, 'title': None, 'year': '1925'}]} Decoded data can be encoded back to XML: .. doctest:: collection >>> obj = schema.decode('tests/test_cases/examples/collection/collection.xml') >>> collection = schema.encode(obj) >>> collection >>> print(xmlschema.etree_tostring(collection, {'col': 'http://example.com/ns/collection'})) 1 The Umbrellas 1886 Pierre-Auguste Renoir 1841-02-25 1919-12-03 painter 10000.00 2 <year>1925</year> <author id="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> </object> </col:collection> All the decoding and encoding methods are based on two generator methods of the `XMLSchema` class, namely *iter_decode()* and *iter_encode()*, that yield both data and validation errors. See :ref:`schema-level-api` section for more information. Decoding a part using XPath --------------------------- If you need to decode only a part of the XML document you can pass also an XPath expression using the *path* argument. .. doctest:: >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> pprint(xs.to_dict('tests/test_cases/examples/vehicles/vehicles.xml', '/vh:vehicles/vh:bikes')) {'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]} .. note:: An XPath expression for the schema *considers the schema as the root element with global elements as its children*. Validating and decoding ElementTree's data ------------------------------------------ Validation and decode API works also with XML data loaded in ElementTree structures: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> from xml.etree import ElementTree >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> xt = ElementTree.parse('tests/test_cases/examples/vehicles/vehicles.xml') >>> xs.is_valid(xt) True >>> pprint(xs.to_dict(xt, process_namespaces=False), depth=2) {'@{http://www.w3.org/2001/XMLSchema-instance}schemaLocation': 'http://...', '{http://example.com/vehicles}bikes': {'{http://example.com/vehicles}bike': [...]}, '{http://example.com/vehicles}cars': {'{http://example.com/vehicles}car': [...]}} The standard ElementTree library lacks of namespace information in trees, so you have to provide a map to convert URIs to prefixes: >>> namespaces = {'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'vh': 'http://example.com/vehicles'} >>> pprint(xs.to_dict(xt, namespaces=namespaces)) {'@xmlns:vh': 'http://example.com/vehicles', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd', 'vh:bikes': {'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]}, 'vh:cars': {'vh:car': [{'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'}]}} You can also convert XML data using the lxml_ library, that works better because namespace information is associated within each node of the trees: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> import lxml.etree as ElementTree >>> xs = xmlschema.XMLSchema('tests/test_cases/examples/vehicles/vehicles.xsd') >>> xt = ElementTree.parse('tests/test_cases/examples/vehicles/vehicles.xml') >>> xs.is_valid(xt) True >>> pprint(xs.to_dict(xt)) {'@xmlns:vh': 'http://example.com/vehicles', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd', 'vh:bikes': {'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]}, 'vh:cars': {'vh:car': [{'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'}]}} >>> pprint(xmlschema.to_dict(xt, 'tests/test_cases/examples/vehicles/vehicles.xsd')) {'@xmlns:vh': 'http://example.com/vehicles', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd', 'vh:bikes': {'vh:bike': [{'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'}]}, 'vh:cars': {'vh:car': [{'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'}]}} Customize the decoded data structure ------------------------------------ Starting from the version 0.9.9 the package includes converter objects, in order to control the decoding process and produce different data structures. These objects intervene at element level to compose the decoded data (attributes and content) into a data structure. The default converter produces a data structure similar to the format produced by previous versions of the package. You can customize the conversion process providing a converter instance or subclass when you create a schema instance or when you want to decode an XML document. For instance you can use the *Badgerfish* converter for a schema instance: .. doctest:: >>> import xmlschema >>> from pprint import pprint >>> xml_schema = 'tests/test_cases/examples/vehicles/vehicles.xsd' >>> xml_document = 'tests/test_cases/examples/vehicles/vehicles.xml' >>> xs = xmlschema.XMLSchema(xml_schema, converter=xmlschema.BadgerFishConverter) >>> pprint(xs.to_dict(xml_document, dict_class=dict), indent=4) { '@xmlns': { 'vh': 'http://example.com/vehicles', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}, 'vh:vehicles': { '@xsi:schemaLocation': 'http://example.com/vehicles ' 'vehicles.xsd', 'vh:bikes': { 'vh:bike': [ { '@make': 'Harley-Davidson', '@model': 'WL'}, { '@make': 'Yamaha', '@model': 'XS650'}]}, 'vh:cars': { 'vh:car': [ { '@make': 'Porsche', '@model': '911'}, { '@make': 'Porsche', '@model': '911'}]}}} You can also change the data decoding process providing the keyword argument *converter* to the method call: .. doctest:: >>> pprint(xs.to_dict(xml_document, converter=xmlschema.ParkerConverter, dict_class=dict), indent=4) {'vh:bikes': {'vh:bike': [None, None]}, 'vh:cars': {'vh:car': [None, None]}} See the :ref:`converters` section for more information about converters. Decoding to JSON ---------------- The data structured created by the decoder can be easily serialized to JSON. But if you data include `Decimal` values (for *decimal* XSD built-in type) you cannot convert the data to JSON: .. doctest:: >>> import xmlschema >>> import json >>> xml_document = 'tests/test_cases/examples/collection/collection.xml' >>> print(json.dumps(xmlschema.to_dict(xml_document), indent=4)) Traceback (most recent call last): File "/usr/lib64/python2.7/doctest.py", line 1315, in __run compileflags, 1) in test.globs File "<doctest default[3]>", line 1, in <module> print(json.dumps(xmlschema.to_dict(xml_document), indent=4)) File "/usr/lib64/python2.7/json/__init__.py", line 251, in dumps sort_keys=sort_keys, **kw).encode(obj) File "/usr/lib64/python2.7/json/encoder.py", line 209, in encode chunks = list(chunks) File "/usr/lib64/python2.7/json/encoder.py", line 434, in _iterencode for chunk in _iterencode_dict(o, _current_indent_level): File "/usr/lib64/python2.7/json/encoder.py", line 408, in _iterencode_dict for chunk in chunks: File "/usr/lib64/python2.7/json/encoder.py", line 332, in _iterencode_list for chunk in chunks: File "/usr/lib64/python2.7/json/encoder.py", line 408, in _iterencode_dict for chunk in chunks: File "/usr/lib64/python2.7/json/encoder.py", line 442, in _iterencode o = _default(o) File "/usr/lib64/python2.7/json/encoder.py", line 184, in default raise TypeError(repr(o) + " is not JSON serializable") TypeError: Decimal('10000.00') is not JSON serializable This problem is resolved providing an alternative JSON-compatible type for `Decimal` values, using the keyword argument *decimal_type*: .. doctest:: >>> print(json.dumps(xmlschema.to_dict(xml_document, decimal_type=str), indent=4)) # doctest: +SKIP { "object": [ { "@available": true, "author": { "qualification": "painter", "born": "1841-02-25", "@id": "PAR", "name": "Pierre-Auguste Renoir", "dead": "1919-12-03" }, "title": "The Umbrellas", "year": "1886", "position": 1, "estimation": "10000.00", "@id": "b0836217462" }, { "@available": true, "author": { "qualification": "painter, sculptor and ceramicist", "born": "1893-04-20", "@id": "JM", "name": "Joan Mir\u00f3", "dead": "1983-12-25" }, "title": null, "year": "1925", "position": 2, "@id": "b0836217463" } ], "@xsi:schemaLocation": "http://example.com/ns/collection collection.xsd" } From version 1.0 there are two module level API for simplify the JSON serialization and deserialization task. See the :meth:`xmlschema.to_json` and :meth:`xmlschema.from_json` in the :ref:`document-level-api` section. XML resources and documents =========================== Schemas and XML instances processing are based on the class :class:`XMLResource`, that handles the loading and the iteration of XSD/XML data. Starting from v1.3.0 :class:`XMLResource` has been empowered with ElementTree-like XPath API. From the same release a new class :class:`xmlschema.XmlDocument` is available for representing XML resources with a related schema: .. doctest:: >>> import xmlschema >>> xml_document = xmlschema.XmlDocument('tests/test_cases/examples/vehicles/vehicles.xml') >>> xml_document.schema XMLSchema10(name='vehicles.xsd', namespace='http://example.com/vehicles') This class can be used to derive specialized schema-related classes. See :ref:`wsdl11-documents` section for an application example.���������������������������������������������������������������������������������������xmlschema-1.10.0/mypy.ini���������������������������������������������������������������������������0000664�0000000�0000000�00000000037�14211403446�0015250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[mypy] show_error_codes = True �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/publiccode.yml���������������������������������������������������������������������0000664�0000000�0000000�00000004460�14211403446�0016411�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # This repository adheres to the publiccode.yml standard by including this # metadata file that makes public software easily discoverable. # More info at https://github.com/italia/publiccode.yml publiccodeYmlVersion: '0.2' name: xmlschema url: 'https://github.com/sissaschool/xmlschema' landingURL: 'https://github.com/sissaschool/xmlschema' releaseDate: '2022-03-07' softwareVersion: v1.10.0 developmentStatus: stable platforms: - linux - windows - mac softwareType: library inputTypes: - text/xml - application/xml - application/json outputTypes: - application/json - application/xml categories: - data-analytics - data-collection maintenance: type: internal contacts: - name: Davide Brunato email: davide.brunato@sissa.it affiliation: ' Scuola Internazionale Superiore di Studi Avanzati' legal: license: MIT mainCopyrightOwner: Scuola Internazionale Superiore di Studi Avanzati repoOwner: Scuola Internazionale Superiore di Studi Avanzati localisation: localisationReady: false availableLanguages: - en it: countryExtensionVersion: '0.2' riuso: codiceIPA: sissa description: en: genericName: xmlschema apiDocumentation: 'https://xmlschema.readthedocs.io/en/latest/api.html' documentation: 'http://xmlschema.readthedocs.io/en/latest/' shortDescription: XML Schema validator and data conversion library for Python longDescription: > The _xmlschema_ library is an implementation of [XML Schema](http://www.w3.org/2001/XMLSchema) for Python (supports Python 3.5+). This library arises from the needs of a solid Python layer for processing XML Schema based files for [MaX (Materials design at the Exascale)](http://www.max-centre.eu/) European project. A significant problem is the encoding and the decoding of the XML data files produced by different simulation software. Another important requirement is the XML data validation, in order to put the produced data under control. The lack of a suitable alternative for Python in the schema-based decoding of XML data has led to build this library. Obviously this library can be useful for other cases related to XML Schema based processing, not only for the original scope. features: - XSD 1.0 and XSD 1.1 validator and decoder ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/requirements-dev.txt���������������������������������������������������������������0000664�0000000�0000000�00000000321�14211403446�0017605�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Requirements for setup a development environment for the xmlschema package. setuptools tox coverage elementpath>=2.5.0, <3.0.0 lxml jinja2 memory_profiler Sphinx sphinx_rtd_theme flake8 mypy lxml-stubs -e . ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/setup.py���������������������������������������������������������������������������0000775�0000000�0000000�00000004755�14211403446�0015301�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /usr/bin/env python # # Copyright (c) 2016-2022, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from setuptools import setup, find_packages from pathlib import Path with Path(__file__).parent.joinpath('README.rst').open() as readme: long_description = readme.read() setup( name='xmlschema', version='1.10.0', packages=find_packages(include=['xmlschema', 'xmlschema.*']), include_package_data=True, entry_points={ 'console_scripts': [ 'xmlschema-validate=xmlschema.cli:validate', 'xmlschema-xml2json=xmlschema.cli:xml2json', 'xmlschema-json2xml=xmlschema.cli:json2xml', ] }, python_requires='>=3.7', install_requires=['elementpath>=2.5.0, <3.0.0'], extras_require={ 'codegen': ['elementpath>=2.5.0, <3.0.0', 'jinja2'], 'dev': ['tox', 'coverage', 'lxml', 'elementpath>=2.5.0, <3.0.0', 'memory_profiler', 'Sphinx', 'sphinx_rtd_theme', 'jinja2', 'flake8', 'mypy', 'lxml-stubs'], 'docs': ['elementpath>=2.5.0, <3.0.0', 'Sphinx', 'sphinx_rtd_theme', 'jinja2'] }, author='Davide Brunato', author_email='brunato@sissa.it', url='https://github.com/sissaschool/xmlschema', license='MIT', license_file='LICENSE', description='An XML Schema validator and decoder', long_description=long_description, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries', 'Topic :: Text Processing :: Markup :: XML', ] ) �������������������xmlschema-1.10.0/tests/�����������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0014713�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/__init__.py������������������������������������������������������������������0000664�0000000�0000000�00000000000�14211403446�0017012�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/check_etree_import.py��������������������������������������������������������0000775�0000000�0000000�00000004067�14211403446�0021132�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ Check ElementTree import with xmlschema. """ import argparse import sys parser = argparse.ArgumentParser(add_help=True) parser.add_argument( '--before', action="store_true", default=False, help="Import ElementTree before xmlschema. If not provided the ElementTree library " "is loaded after xmlschema." ) args = parser.parse_args() if args.before: print("Importing ElementTree before xmlschema ...") import xml.etree.ElementTree as ElementTree import xmlschema.etree else: print("Importing ElementTree after xmlschema ...") import xmlschema.etree import xml.etree.ElementTree as ElementTree # Check if all modules are loaded in the system table assert 'xml.etree.ElementTree' in sys.modules, "ElementTree not loaded!" assert 'xmlschema' in sys.modules, 'xmlschema not loaded' assert 'xmlschema.etree' in sys.modules, 'xmlschema.etree not loaded' assert '_elementtree' in sys.modules, "cElementTree is not loaded!" # Check imported ElementTree assert ElementTree._Element_Py is not ElementTree.Element, "ElementTree is pure Python!" assert xmlschema.etree.ElementTree is ElementTree, \ "xmlschema has a different ElementTree module!" assert sys.modules['xml.etree'].ElementTree is ElementTree # Check ElementTree and pure Python ElementTree imported in xmlschema PyElementTree = xmlschema.etree.PyElementTree assert xmlschema.etree.ElementTree.Element is not xmlschema.etree.ElementTree._Element_Py, \ "xmlschema's ElementTree is pure Python!" assert PyElementTree.Element is PyElementTree._Element_Py, \ "PyElementTree is not pure Python!" assert xmlschema.etree.ElementTree is not PyElementTree, \ "xmlschema ElementTree is PyElementTree!" print("\nTest OK: ElementTree import is working as expected!") �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/check_memory.py��������������������������������������������������������������0000775�0000000�0000000�00000011364�14211403446�0017742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ Check xmlschema package memory usage. Refs: https://pypi.org/project/memory_profiler/ https://github.com/brunato/xmlschema/issues/32 """ import argparse from memory_profiler import profile def test_choice_type(value): if value not in (str(v) for v in range(1, 9)): msg = "%r must be an integer between [1 ... 8]." % value raise argparse.ArgumentTypeError(msg) return int(value) parser = argparse.ArgumentParser(add_help=True) parser.usage = """%(prog)s TEST_NUM [XML_FILE [REPEAT]] Run memory tests: 1) Package import or schema build 2) Iterate XML file with parse 3) Iterate XML file with full iterparse 4) Iterate XML file with emptied iterparse 5) Decode XML file with xmlschema 6) Decode XML file with xmlschema in lazy mode 7) Validate XML file with xmlschema 8) Validate XML file with xmlschema in lazy mode """ parser.add_argument('test_num', metavar="TEST_NUM", type=test_choice_type, help="Test number to run") parser.add_argument('xml_file', metavar='XML_FILE', nargs='?', help='Input XML file') parser.add_argument('repeat', metavar='REPEAT', nargs='?', type=int, default=1, help='Repeat operation N times') args = parser.parse_args() # noinspection PyUnresolvedReferences @profile def import_package(): # Imports of packages used by xmlschema that # have a significant memory usage impact. import decimal from urllib.error import URLError import lxml.etree import elementpath import xmlschema return xmlschema @profile def build_schema(source): xs = xmlschema.XMLSchema(source) return xs @profile def etree_parse(source, repeat=1): xt = ElementTree.parse(source) for _ in range(repeat): for _ in xt.iter(): pass @profile def etree_full_iterparse(source, repeat=1): for _ in range(repeat): context = ElementTree.iterparse(source, events=('start', 'end')) for event, elem in context: if event == 'start': pass @profile def etree_emptied_iterparse(source, repeat=1): for _ in range(repeat): context = ElementTree.iterparse(source, events=('start', 'end')) for event, elem in context: if event == 'end': elem.clear() @profile def decode(source, repeat=1): decoder = xmlschema.XMLSchema.meta_schema if source.endswith('.xsd') else xmlschema for _ in range(repeat): decoder.to_dict(source) @profile def lazy_decode(source, repeat=1): if source.endswith('.xsd'): decoder = xmlschema.XMLSchema.meta_schema.iter_decode else: decoder = xmlschema.iter_decode for _ in range(repeat): for _result in decoder(xmlschema.XMLResource(source, lazy=True), path='*'): del _result @profile def validate(source, repeat=1): validator = xmlschema.XMLSchema.meta_schema if source.endswith('.xsd') else xmlschema for _ in range(repeat): validator.validate(source) @profile def lazy_validate(source, repeat=1): if source.endswith('.xsd'): validator, path = xmlschema.XMLSchema.meta_schema, '*' else: validator, path = xmlschema, None for _ in range(repeat): validator.validate(xmlschema.XMLResource(source, lazy=True), path=path) if __name__ == '__main__': if args.test_num == 1: if args.xml_file is None: import_package() else: import xmlschema build_schema(args.xml_file) elif args.test_num == 2: import xml.etree.ElementTree as ElementTree etree_parse(args.xml_file, args.repeat) elif args.test_num == 3: import xml.etree.ElementTree as ElementTree etree_full_iterparse(args.xml_file, args.repeat) elif args.test_num == 4: import xml.etree.ElementTree as ElementTree etree_emptied_iterparse(args.xml_file, args.repeat) elif args.test_num == 5: import xmlschema xmlschema.XMLSchema.meta_schema.build() decode(args.xml_file, args.repeat) elif args.test_num == 6: import xmlschema xmlschema.XMLSchema.meta_schema.build() lazy_decode(args.xml_file, args.repeat) elif args.test_num == 7: import xmlschema xmlschema.XMLSchema.meta_schema.build() validate(args.xml_file, args.repeat) elif args.test_num == 8: import xmlschema xmlschema.XMLSchema.meta_schema.build() lazy_validate(args.xml_file, args.repeat) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/�������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0016711�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/demo/��������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017635�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/demo/demo_type_filter_test.jinja�����������������������������������0000664�0000000�0000000�00000000047�14211403446�0025244�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|demo_type }}�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/�����������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020361�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/name_filter_test.jinja�������������������������������������0000664�0000000�0000000�00000000042�14211403446�0024716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|name }}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/namespace_filter_test.jinja��������������������������������0000664�0000000�0000000�00000000047�14211403446�0025737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|namespace }}�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/python_type_filter_test.jinja������������������������������0000664�0000000�0000000�00000000052�14211403446�0026361�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|python_type }} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/qname_filter_test.jinja������������������������������������0000664�0000000�0000000�00000000043�14211403446�0025100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|qname }}���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/sort_types_filter_test.jinja�������������������������������0000664�0000000�0000000�00000000127�14211403446�0026215�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{%- for type in ( schema.types|sort_types ) %} {{- type.local_name }} {%- endfor %}�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/type_name_filter_test.jinja��������������������������������0000664�0000000�0000000�00000000047�14211403446�0025764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|type_name }}�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/type_qname_filter_test.jinja�������������������������������0000664�0000000�0000000�00000000050�14211403446�0026137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|type_qname }}����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/unknown_filter_test.jinja����������������������������������0000664�0000000�0000000�00000000045�14211403446�0025500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|unknown }}�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/templates/filters/wrong-template.jinja���������������������������������������0000664�0000000�0000000�00000000052�14211403446�0024340�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{{ schema.elements['root']|name }} {{ { }}��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_all.py������������������������������������������������������������������0000664�0000000�0000000�00000006762�14211403446�0017107�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # if __name__ == '__main__': import unittest import os import platform from xmlschema.testing import factory_tests, make_schema_test_class, \ make_validation_test_class, get_test_program_args_parser DEFAULT_TESTFILES = os.path.join(os.path.dirname(__file__), 'test_cases/testfiles') def load_tests(loader, tests, pattern): tests_dir = os.path.dirname(__file__) if pattern is not None: tests.addTests(loader.discover(start_dir=tests_dir, pattern=pattern)) return tests tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_etree.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_etree_import.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_helpers.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_namespaces.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_resources.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_regex.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_xpath.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_cli.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_converters.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_documents.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_dataobjects.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_codegen.py")) tests.addTests(loader.discover(start_dir=tests_dir, pattern="test_wsdl.py")) validation_dir = os.path.join(os.path.dirname(__file__), 'validation') tests.addTests(loader.discover(start_dir=validation_dir, pattern='test_*.py')) validators_dir = os.path.join(os.path.dirname(__file__), 'validators') tests.addTests(loader.discover(start_dir=validators_dir, pattern="test_*.py")) return tests args = get_test_program_args_parser(DEFAULT_TESTFILES).parse_args() schema_tests = factory_tests( test_class_builder=make_schema_test_class, testfiles=args.testfiles, suffix='xsd', check_with_lxml=args.lxml, codegen=args.codegen, verbosity=args.verbosity, ) globals().update(schema_tests) validation_tests = factory_tests( test_class_builder=make_validation_test_class, testfiles=args.testfiles, suffix='xml', check_with_lxml=args.lxml, codegen=args.codegen, verbosity=args.verbosity, ) globals().update(validation_tests) argv = [__file__] if args.tb_locals: argv.append('--local') for pattern_ in args.patterns: argv.append('-k') argv.append(pattern_) header_template = "Test xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main(argv=argv, verbosity=args.verbosity, failfast=args.failfast, catchbreak=args.catchbreak, buffer=args.buffer) ��������������xmlschema-1.10.0/tests/test_cases/������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017050�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/���������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020666�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/����������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0023021�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection-1_error.xml������������������������0000664�0000000�0000000�00000001635�14211403446�0027252�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection.xsd"> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 Pierre-Auguste Renoir 1841-02-25 1919-12-03 painter 10000.00 2.0 <year>1925</year> <author id="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> </object> </col:collection> ���������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection.py���������������������������������0000664�0000000�0000000�00000001437�14211403446�0025533�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # Auto-generated code: don't edit this file # """ Sample of XML data bindings for schema collection.xsd """ import xmlschema from xmlschema.dataobjects import DataElement, DataBindingMeta __NAMESPACE__ = "http://example.com/ns/collection" schema = xmlschema.XMLSchema11("collection.xsd") class CollectionBinding(DataElement, metaclass=DataBindingMeta): xsd_element = schema.elements['collection'] class PersonBinding(DataElement, metaclass=DataBindingMeta): xsd_element = schema.elements['person'] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection.xml��������������������������������0000664�0000000�0000000�00000001633�14211403446�0025701�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection.xsd"> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 Pierre-Auguste Renoir 1841-02-25 1919-12-03 painter 10000.00 2 <year>1925</year> <author id="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> </object> </col:collection> �����������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection.xsd��������������������������������0000664�0000000�0000000�00000003077�14211403446�0025703�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="http://example.com/ns/collection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/ns/collection"> <xs:element name="collection"> <xs:complexType> <xs:sequence> <xs:element name="object" type="objType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="born" type="xs:date"/> <xs:element name="dead" type="xs:date" minOccurs="0"/> <xs:element name="qualification" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> </xs:complexType> <xs:complexType name="objType"> <xs:sequence> <xs:element name="position" type="xs:int"/> <xs:element name="title" type="xs:string"/> <xs:element name="year" type="xs:gYear"/> <xs:element name="author" type="personType"/> <xs:element name="estimation" type="xs:decimal" minOccurs="0"/> <xs:element name="characters" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element ref="person" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="available" type="xs:boolean" use="required"/> </xs:complexType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection2.xml�������������������������������0000664�0000000�0000000�00000001655�14211403446�0025767�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection2.xsd"> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 Pierre-Auguste Renoir 1841-02-25 1919-12-03 painter 10000.00 2 <year>1925</year> <author dn="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> </object> </col:collection> �����������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection2.xsd�������������������������������0000664�0000000�0000000�00000003310�14211403446�0025753�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="http://example.com/ns/collection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/ns/collection"> <xs:element name="collection"> <xs:complexType> <xs:sequence> <xs:element name="object" type="objType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:key name="author_key_constraint"> <xs:selector xpath="object/author"/> <xs:field xpath="@dn"/> </xs:key> </xs:element> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="born" type="xs:date"/> <xs:element name="dead" type="xs:date" minOccurs="0"/> <xs:element name="qualification" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="dn" type="xs:string" use="required"/> </xs:complexType> <xs:complexType name="objType"> <xs:sequence> <xs:element name="position" type="xs:int"/> <xs:element name="title" type="xs:string"/> <xs:element name="year" type="xs:gYear"/> <xs:element name="author" type="personType"/> <xs:element name="estimation" type="xs:decimal" minOccurs="0"/> <xs:element name="characters" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element ref="person" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="available" type="xs:boolean" use="required"/> </xs:complexType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection3.xml�������������������������������0000664�0000000�0000000�00000001700�14211403446�0025757�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection3.xsd"> <author dn="PAR"> <name>Pierre-Auguste Renoir</name> <born>1841-02-25</born> <dead>1919-12-03</dead> <qualification>painter</qualification> </author> <author dn="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 PARQ 10000.00 2 <year>1925</year> <author>JM</author> </object> </col:collection> ����������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection3.xsd�������������������������������0000664�0000000�0000000�00000003622�14211403446�0025762�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="http://example.com/ns/collection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/ns/collection"> <xs:element name="collection"> <xs:complexType> <xs:sequence> <xs:element name="author" type="personType" maxOccurs="unbounded"/> <xs:element name="object" type="objType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:keyref name="author_dn_ref" refer="author_dn"> <xs:selector xpath="object"/> <xs:field xpath="author"/> </xs:keyref> <xs:key name="author_dn"> <xs:selector xpath="author"/> <xs:field xpath="@dn"/> </xs:key> </xs:element> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="born" type="xs:date"/> <xs:element name="dead" type="xs:date" minOccurs="0"/> <xs:element name="qualification" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="dn" type="xs:string" use="required"/> </xs:complexType> <xs:complexType name="objType"> <xs:sequence> <xs:element name="position" type="xs:int"/> <xs:element name="title" type="xs:string"/> <xs:element name="year" type="xs:gYear"/> <xs:element name="author" type="xs:string"/> <xs:element name="estimation" type="xs:decimal" minOccurs="0"/> <xs:element name="characters" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element ref="person" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="available" type="xs:boolean" use="required"/> </xs:complexType> </xs:schema> ��������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection3bis.xml����������������������������0000664�0000000�0000000�00000002072�14211403446�0026460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Invalid because collection3bis.xsd puts the xs:key on single element and the 2nd author overrides the first. --> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection3bis.xsd"> <author dn="PAR"> <name>Pierre-Auguste Renoir</name> <born>1841-02-25</born> <dead>1919-12-03</dead> <qualification>painter</qualification> </author> <author dn="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 PAR 10000.00 2 <year>1925</year> <author>JM</author> </object> </col:collection> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection3bis.xsd����������������������������0000664�0000000�0000000�00000003673�14211403446�0026466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="http://example.com/ns/collection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/ns/collection"> <xs:element name="collection"> <xs:complexType> <xs:sequence> <xs:element name="author" type="personType" maxOccurs="unbounded"> <xs:key name="author_dn"> <xs:selector xpath="."/> <xs:field xpath="@dn"/> </xs:key> </xs:element> <xs:element name="object" type="objType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:keyref name="author_dn_ref" refer="author_dn"> <xs:selector xpath="object"/> <xs:field xpath="author"/> </xs:keyref> </xs:element> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="born" type="xs:date"/> <xs:element name="dead" type="xs:date" minOccurs="0"/> <xs:element name="qualification" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="dn" type="xs:string" use="required"/> </xs:complexType> <xs:complexType name="objType"> <xs:sequence> <xs:element name="position" type="xs:int"/> <xs:element name="title" type="xs:string"/> <xs:element name="year" type="xs:gYear"/> <xs:element name="author" type="xs:string"/> <xs:element name="estimation" type="xs:decimal" minOccurs="0"/> <xs:element name="characters" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element ref="person" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="available" type="xs:boolean" use="required"/> </xs:complexType> </xs:schema> ���������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection4.xml�������������������������������0000664�0000000�0000000�00000002524�14211403446�0025765�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Header comment --> <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection.xsd"> <!-- First object --> <object id="b0836217462" available="true"> <position>1</position> <title>The Umbrellas 1886 Pierre-Auguste Renoir 1841-02-25 1919-12-03 painter 10000.00 2 <year>1925</year> <!-- Inner comment #7 --> <author id="JM"> <name>Joan Miró</name> <!-- Inner comment #8 --> <born>1893-04-20</born> <dead>1983-12-25</dead> <!-- Inner comment #9 --> <qualification>painter, sculptor and ceramicist</qualification> <!-- Inner comment #10 --> </author> </object> <!-- Last inner comment --> </col:collection> <!-- Last comment --> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/collection/collection4.xsd�������������������������������0000664�0000000�0000000�00000003317�14211403446�0025764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Collection schema with XSD namespace bound to more prefixes. --> <xs:schema targetNamespace="http://example.com/ns/collection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/ns/collection"> <xs:element name="collection"> <xs:complexType> <xs:sequence> <xs:element name="object" type="objType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence xmlns="http://www.w3.org/2001/XMLSchema"> <xs:element name="name" type="string"/> <!-- xs:string --> <xs:element name="born" type="date"/> <!-- xs:date --> <xs:element name="dead" type="xs:date" minOccurs="0"/> <xs:element name="qualification" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> </xs:complexType> <xs:complexType name="objType"> <xs:sequence> <xs:element name="position" type="xs:int"/> <xs:element name="title" type="xs:string"/> <xs:element name="year" type="xs:gYear"/> <xs:element name="author" type="personType"/> <xs:element name="estimation" type="xs:decimal" minOccurs="0"/> <xs:element name="characters" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element ref="person" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> <xs:attribute name="available" type="xs:boolean" use="required"/> </xs:complexType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/stockquote/����������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0023067�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/stockquote/stockquote.wsdl�������������������������������0000664�0000000�0000000�00000002017�14211403446�0026163�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- From WSDL 1.1 definition: https://www.w3.org/TR/2001/NOTE-wsdl-20010315 --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/definitions" xmlns:tns="http://example.com/stockquote/definitions" xmlns:xsd1="http://example.com/stockquote/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/schemas" location="stockquote.xsd" /> <message name="GetLastTradePriceInput"> <part name="body" element="xsd1:TradePriceRequest"/> </message> <message name="GetLastTradePriceOutput"> <part name="body" element="xsd1:TradePrice"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceInput"/> <output message="tns:GetLastTradePriceOutput"/> </operation> </portType> </definitions>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/stockquote/stockquote.xsd��������������������������������0000664�0000000�0000000�00000001230�14211403446�0026004�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- From WSDL 1.1 definition: https://www.w3.org/TR/2001/NOTE-wsdl-20010315 --> <xs:schema targetNamespace="http://example.com/stockquote/schemas" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="TradePriceRequest"> <xs:complexType> <xs:all> <xs:element name="tickerSymbol" type="xs:string"/> </xs:all> </xs:complexType> </xs:element> <xs:element name="TradePrice"> <xs:complexType> <xs:all> <xs:element name="price" type="xs:float"/> </xs:all> </xs:complexType> </xs:element> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/stockquote/stockquoteservice.wsdl������������������������0000664�0000000�0000000�00000002316�14211403446�0027546�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/service" xmlns:tns="http://example.com/stockquote/service" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:defs="http://example.com/stockquote/definitions" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/definitions" location="stockquote.wsdl"/> <binding name="StockQuoteBinding" type="defs:StockQuotePortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://example.com/GetLastTradePrice"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022470�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/bikes.xsd���������������������������������������0000664�0000000�0000000�00000000727�14211403446�0024313�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="types.xsd" /> <xs:element name="bikes"> <xs:complexType> <xs:sequence> <xs:element name="bike" type="vh:vehicleType" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> �����������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/cars.xsd����������������������������������������0000664�0000000�0000000�00000000725�14211403446�0024144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="types.xsd" /> <xs:element name="cars"> <xs:complexType> <xs:sequence> <xs:element name="car" type="vh:vehicleType" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> �������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/types.xsd���������������������������������������0000664�0000000�0000000�00000000551�14211403446�0024355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/vehicles" targetNamespace="http://example.com/vehicles"> <xs:include schemaLocation="cars.xsd" /> <xs:complexType name="vehicleType"> <xs:attribute name="make" type="xs:string" /> <xs:attribute name="model" type="xs:string" /> </xs:complexType> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles-1_error.xml����������������������������0000664�0000000�0000000�00000000724�14211403446�0026366�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<vh:vehicles xmlns:vh="http://example.com/vehicles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/vehicles vehicles.xsd"> <vh:cars> NOT ALLOWED CHARACTER DATA <vh:car make="Porsche" model="911" /> <vh:car make="Porsche" model="911" /> </vh:cars> <vh:bikes> <vh:bike make="Harley-Davidson" model="WL" /> <vh:bike make="Yamaha" model="XS650" /> </vh:bikes> </vh:vehicles> ��������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles-2_errors.xml���������������������������0000664�0000000�0000000�00000000733�14211403446�0026552�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<vh:vehicles xmlns:vh="http://example.com/vehicles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/vehicles vehicles.xsd"> <vh:cars> CHARACTER DATA <vh:car make="Porsche" model="911" /> <vh:car make="Porsche" model="911" /> </vh:cars> <vh:bikes> <vh:bike make="Harley-Davidson" model="WL" /> N/A CHARACTERS <vh:bike make="Yamaha" model="XS650" /> </vh:bikes> </vh:vehicles> �������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles-3_errors.xml���������������������������0000664�0000000�0000000�00000000753�14211403446�0026555�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<vh:vehicles xmlns:vh="http://example.com/vehicles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/vehicles vehicles.xsd"> <vh:cars> NOT ALLOWED CHARACTER DATA <vh:car make="Porsche" color="blue" model="911" /> <vh:car make="Porsche" model="911" /> </vh:cars> <vh:bikes> <vh:bike make="Harley-Davidson" model="WL" /> EXTRA <vh:bike make="Yamaha" model="XS650" /> </vh:bikes> </vh:vehicles> ���������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles-max.xsd��������������������������������0000664�0000000�0000000�00000001055�14211403446�0025576�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="cars.xsd"/> <xs:include schemaLocation="bikes.xsd"/> <xs:element name="vehicles"> <xs:complexType> <xs:sequence maxOccurs="5"> <xs:element ref="vh:cars" /> <xs:element ref="vh:bikes" /> </xs:sequence> </xs:complexType> </xs:element> <xs:attribute type="xs:positiveInteger" name="step"/> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles.xml������������������������������������0000664�0000000�0000000�00000000761�14211403446�0025020�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <vh:vehicles xmlns:vh="http://example.com/vehicles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/vehicles vehicles.xsd"> <vh:cars> <vh:car make="Porsche" model="911" /> <!-- Comment --> <vh:car make="Porsche" model="911" /> </vh:cars> <vh:bikes> <vh:bike make="Harley-Davidson" model="WL" /> <vh:bike make="Yamaha" model="XS650" /> </vh:bikes> </vh:vehicles> ���������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles.xsd������������������������������������0000664�0000000�0000000�00000001037�14211403446�0025013�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="cars.xsd"/> <xs:include schemaLocation="bikes.xsd"/> <xs:element name="vehicles"> <xs:complexType> <xs:sequence> <xs:element ref="vh:cars" /> <xs:element ref="vh:bikes" /> </xs:sequence> </xs:complexType> </xs:element> <xs:attribute type="xs:positiveInteger" name="step"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/examples/vehicles/vehicles2.xml�����������������������������������0000664�0000000�0000000�00000000660�14211403446�0025100�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <vh:vehicles xmlns:vh="http://example.com/vehicles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/vehicles vehicles.xsd"> <vh:cars> <vh:car make="Porsche" model="911" /> <vh:car make="Porsche" model="911" /> </vh:cars> <vh:bikes> <vh:bike make="Harley-Davidson" model="WL" /> </vh:bikes> </vh:vehicles> ��������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/���������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020666�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/attributes/����������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0023054�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/attributes/default_attributes-missing_group.xsd����������0000664�0000000�0000000�00000001260�14211403446�0032350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- XSD 1.1 schema example with defaultAttributes --> <xs:schema xmlns:ns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" defaultAttributes="ns:default_attrs"> <xs:element name="tree"> <xs:complexType defaultAttributesApply="false"> <xs:sequence> <xs:element name="node" maxOccurs="unbounded" type="ns:node-type"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="node-type" mixed="true"> <xs:simpleContent> <xs:extension base="xs:string"/> </xs:simpleContent> </xs:complexType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/attributes/default_attributes.xsd������������������������0000664�0000000�0000000�00000001616�14211403446�0027472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- XSD 1.1 schema example with defaultAttributes --> <xs:schema xmlns:ns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" defaultAttributes="ns:default_attrs"> <xs:attributeGroup name="default_attrs"> <xs:attribute name="node-id" type="xs:positiveInteger" use="required"/> <xs:attribute name="colour" type="xs:token"/> </xs:attributeGroup> <xs:element name="tree"> <xs:complexType defaultAttributesApply="false"> <xs:sequence> <xs:element name="node" maxOccurs="unbounded" form="qualified" type="ns:node-type"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="node-type" mixed="true"> <xs:simpleContent> <xs:extension base="xs:string"/> </xs:simpleContent> </xs:complexType> </xs:schema> ������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/builtins/������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022517�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/builtins/builtins.xml������������������������������������0000664�0000000�0000000�00000001110�14211403446�0025063�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./builtins.xsd"> <birthdayDate>2005-05-25</birthdayDate> <birthdayDate>2001-01-01Z</birthdayDate> <birthdayDate>-0100-07-13</birthdayDate> <eventTime>00:00:00</eventTime> <eventTime>12:30:20.5555</eventTime> <eventTime>12:30:20-04:00</eventTime> <lastTicketDateTime>2017-09-06T23:59:00.000+03:00</lastTicketDateTime> <lastTicketDateTime>2017-09-06T23:59:00+03:00</lastTicketDateTime> </ns:data> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/builtins/builtins.xsd������������������������������������0000664�0000000�0000000�00000001131�14211403446�0025064�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="data"> <xs:complexType> <xs:sequence> <xs:element name="birthdayDate" type="xs:date" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="eventTime" type="xs:time" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="lastTicketDateTime" type="xs:dateTime" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022273�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/data.xml�����������������������������������������0000664�0000000�0000000�00000001337�14211403446�0023732�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./simple-types.xsd"> <decimal_value>1</decimal_value> <certification Year="1999">ISO-9001</certification> <certification Year="2009">ISO-27001</certification> <menù>baccalà mantecato</menù> <complex_boolean Type="2">true</complex_boolean> <complex_boolean Type="1">false</complex_boolean> <complex_boolean>true</complex_boolean> <complex_boolean>false</complex_boolean> <simple_boolean>true</simple_boolean> <simple_boolean>false</simple_boolean> <date_and_time>2020-03-05T23:04:10.047</date_and_time> <hexbin>AABBCCDD</hexbin> </ns:data> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/data2.xml����������������������������������������0000664�0000000�0000000�00000001325�14211403446�0024011�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./simple-types.xsd"> <decimal_value>000000000611.000</decimal_value> <celsiusBodyTemp>37.0</celsiusBodyTemp> <celsiusBodyTemp>0500.0</celsiusBodyTemp> <celsiusBodyTemp>500.00</celsiusBodyTemp> <celsiusBodyTemp>50000.0</celsiusBodyTemp> <certification Year="1999">ISO-9001</certification> <certification Year="2009">ISO-27001</certification> <menù>baccalà mantecato</menù> <config>foo alternative</config> <dateTimeWithTZOffset>2018-10-10T13:57:53.0702116-04:00</dateTimeWithTZOffset> <duration>P1Y2M3DT3H40M</duration> </ns:data> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/data3.xml����������������������������������������0000664�0000000�0000000�00000001140�14211403446�0024005�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./simple-types.xsd"> <decimal_value>abc</decimal_value> <celsiusBodyTemp>37.0</celsiusBodyTemp> <celsiusBodyTemp>zero</celsiusBodyTemp> <celsiusBodyTemp>500.00</celsiusBodyTemp> <celsiusBodyTemp>50000.0</celsiusBodyTemp> <certification Year="1999">ISO-9001</certification> <certification Year="2009">ISO-27001</certification> <menù>baccalà mantecato</menù> <date_and_time> 2017-10-21T13:00:00 </date_and_time> </ns:data> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/data4-mixed.xml����������������������������������0000664�0000000�0000000�00000000740�14211403446�0025117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./mixed-content.xsd"> A decimal value: <decimal_value>10.0</decimal_value> A datetime value: <date_and_time> 2017-10-21T13:00:00 </date_and_time> <!-- spaces are collapsed --> A boolean value: <boolean_value>true</boolean_value> A string: <string_value>abc</string_value> End of data </ns:data> ��������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/long-sequence-1.xsd������������������������������0000664�0000000�0000000�00000001263�14211403446�0025720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="data"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="chunk" type="chunkType"/> <xs:element name="number" type="xs:int"/> <xs:element name="name" type="xs:string"/> <xs:element name="hexbin" type="xs:hexBinary"/> </xs:choice> </xs:complexType> </xs:element> <xs:complexType name="chunkType"> <xs:sequence> <xs:any maxOccurs="unbounded" processContents="lax"/> </xs:sequence> </xs:complexType> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/mixed-content.xsd��������������������������������0000664�0000000�0000000�00000001327�14211403446�0025574�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="data"> <xs:complexType mixed="true"> <xs:choice maxOccurs="unbounded"> <xs:element name="decimal_value" type="xs:decimal"/> <xs:element name="string_value" type="xs:string"/> <xs:element name="boolean_value" type="xs:boolean"/> <xs:element name="date_and_time" type="xs:dateTime"/> <xs:element name="interval" type="xs:duration"/> <xs:element name="hexbin" type="xs:hexBinary"/> </xs:choice> </xs:complexType> </xs:element> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/decoder/simple-types.xsd���������������������������������0000664�0000000�0000000�00000013300�14211403446�0025443�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="data"> <xs:complexType> <xs:sequence> <xs:element name="decimal_value" type="Decimal_9_5" maxOccurs="unbounded"/> <xs:element name="celsiusBodyTemp" type="celsiusBodyTemp" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="certification" type="year_attr_string_75" maxOccurs="unbounded"/> <xs:element name="menù" type="xs:string"/> <xs:element name="complex_boolean" type="TYPE_ATTR_BOOLEAN" minOccurs="0" maxOccurs="4"/> <xs:element name="simple_boolean" type="xs:boolean" minOccurs="0" maxOccurs="4"/> <xs:element name="date_and_time" type="xs:dateTime" minOccurs="0"/> <xs:element name="name" type="none_empty_string" minOccurs="0"/> <xs:element name="config" type="config" minOccurs="0"/> <xs:element name="dateTimeWithTZOffset" type="xs:dateTime" minOccurs="0"/> <xs:element name="duration" type="xs:duration" minOccurs="0"/> <xs:element name="hexbin" type="hexCode" minOccurs="0" /> <xs:element name="base64bin" type="base64Code" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> <xs:simpleType name="Decimal_9_5"> <xs:restriction base="xs:decimal"> <xs:totalDigits value="9"/> <xs:fractionDigits value="5"/> </xs:restriction> </xs:simpleType> <xs:simpleType name='celsiusBodyTemp'> <xs:restriction base='xs:decimal'> <xs:totalDigits value='4'/> <xs:fractionDigits value='1'/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string_75"> <xs:restriction base="xs:string"> <xs:maxLength value="75"/> </xs:restriction> </xs:simpleType> <xs:complexType name="year_attr_string_75"> <xs:simpleContent> <xs:extension base="string_75"> <xs:attribute name="Year" type="xs:integer"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="TYPE_ATTR_BOOLEAN"> <xs:simpleContent> <xs:extension base="xs:boolean"> <xs:attribute name="Type" type="xs:integer"/> </xs:extension> </xs:simpleContent> </xs:complexType> <!-- List types --> <xs:simpleType name="list_of_strings"> <xs:list itemType="xs:string"/> </xs:simpleType> <xs:simpleType name="list_of_integers"> <xs:list itemType="xs:integer"/> </xs:simpleType> <xs:simpleType name="list_of_floats"> <xs:list itemType="xs:float"/> </xs:simpleType> <xs:simpleType name="list_of_booleans"> <xs:list itemType="xs:boolean"/> </xs:simpleType> <!-- Union types --> <xs:simpleType name="integer_or_float"> <xs:union memberTypes="xs:integer xs:float"/> </xs:simpleType> <xs:simpleType name="integer_or_string"> <xs:union memberTypes="xs:integer xs:string"/> </xs:simpleType> <xs:simpleType name="boolean_or_integer_or_string"> <xs:union memberTypes="xs:boolean xs:integer xs:string"/> </xs:simpleType> <!-- For testing issue #63 --> <xs:simpleType name='hexCode'> <xs:restriction base='xs:hexBinary'> <xs:length value='4'/> </xs:restriction> </xs:simpleType> <xs:simpleType name='base64Code'> <xs:restriction base='xs:base64Binary'> <xs:minLength value='3'/> <xs:maxLength value='8'/> </xs:restriction> </xs:simpleType> <xs:simpleType name='base64Length4'> <xs:restriction base='xs:base64Binary'> <xs:length value='4'/> </xs:restriction> </xs:simpleType> <xs:simpleType name='base64Length5'> <xs:restriction base='xs:base64Binary'> <xs:length value='5'/> </xs:restriction> </xs:simpleType> <!-- For testing issue #64 --> <xs:simpleType name="none_empty_string"> <xs:restriction base="xs:string"> <xs:minLength value="1" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="NameType"> <xs:restriction base="xs:string"> <xs:minLength value="1"/> <xs:maxLength value="255"/> </xs:restriction> </xs:simpleType> <!-- For testing issue #83 --> <xs:simpleType name="config"> <xs:restriction base="xs:string"> <xs:whiteSpace value="collapse"/> <xs:pattern value="(word|other)|(alternative)"/> </xs:restriction> </xs:simpleType> <!-- Issue #103 --> <xs:simpleType name="myType"> <xs:union memberTypes="typeA typeB"/> </xs:simpleType> <xs:simpleType name="typeA"> <xs:restriction base="xs:decimal"> <xs:minInclusive value="0.0"/> <xs:maxInclusive value="100.0"/> <xs:fractionDigits value="3"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="typeB"> <xs:restriction base="xs:string"> <xs:pattern value="NaN"/> </xs:restriction> </xs:simpleType> <!-- For testing encoding --> <xs:simpleType name="mdate"> <xs:restriction base="xs:date"> <xs:minInclusive value="2000-01-01" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> <xs:enumeration value="three"/> </xs:restriction> </xs:simpleType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/���������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0023215�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/complex-extensions.xsd�����������������������0000664�0000000�0000000�00000003644�14211403446�0027610�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="ns" targetNamespace="ns"> <!-- Case 1: Legal complexContent extension (base complex content type is empty) --> <xs:complexType name="word"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="language" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="external-word"> <xs:complexContent> <xs:extension base="word"> <xs:attribute name="other-language" default="italian"/> </xs:extension> </xs:complexContent> </xs:complexType> <!-- Case 2: Illegal complexContent extension with different content type --> <xs:complexType name="personType" mixed="true"> <xs:sequence> <xs:element name="firstName" type="xs:string"/> <xs:element name="lastName" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="extPersonType"> <xs:complexContent> <xs:extension base="personType"> <xs:sequence> <xs:element name="birthDate" type="xs:date"/> <xs:element name="age" type="xs:short"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <!-- Case 3: admitted complexContent extension from a simpleContent base --> <xs:complexType name="derivedComplexContentType"> <xs:complexContent> <xs:extension base="complexBaseExpression"> <xs:attribute name="resetTypeRef" type="xs:Name"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="unsignedBitExpression"> <xs:simpleContent> <xs:extension base="complexBaseExpression"/> </xs:simpleContent> </xs:complexType> <xs:complexType name="complexBaseExpression"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="dummy" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/complex-with-simple-content-restriction.xsd��0000664�0000000�0000000�00000001226�14211403446�0033660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Extends an attribute-only complexType with a simple content --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="value" type="int-node"/> <xs:complexType name="node-type" mixed="true"> <xs:attribute name="choice" type="xs:string"/> </xs:complexType> <xs:complexType name="int-node"> <xs:simpleContent> <xs:restriction base="node-type"> <xs:simpleType> <xs:restriction base="xs:int"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/invalid_enumeration_restriction.xsd����������0000664�0000000�0000000�00000001127�14211403446�0032417�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- Invalid enumeration restriction related to issue #202 --> <xs:simpleType name="LocalEnergyProductType"> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="8716867000016" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="LocalRestrictedEnergyProductType"> <xs:restriction base="LocalEnergyProductType"> <xs:enumeration value="A01"/> <!-- not a valid value for base type --> </xs:restriction> </xs:simpleType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/invalid_restrictions1.xsd��������������������0000664�0000000�0000000�00000004003�14211403446�0030251�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for invalid restricted models: UPA violation restricting a substitution group head. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element type="xs:string" name="elem1"/> <xs:element type="xs:string" name="elem2" substitutionGroup="elem1" /> <xs:complexType name="basicType1"> <xs:sequence> <xs:element ref="elem1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <!-- UPA violation minOccurs < maxOccurs --> <xs:complexType name="restrictedType1"> <xs:complexContent> <xs:restriction base="basicType1"> <xs:sequence> <xs:element ref="elem2" maxOccurs="unbounded"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> <!-- No UPA violation if the restricted element is empty but elem2 is not a restriction --> <xs:complexType name="restrictedType2"> <xs:complexContent> <xs:restriction base="basicType1"> <xs:sequence> <xs:element ref="elem2" minOccurs="0" maxOccurs="0"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element type="xs:string" name="elem3" abstract="true"/> <xs:element type="xs:string" name="elem4" substitutionGroup="elem3" /> <xs:complexType name="basicType3"> <xs:sequence> <xs:element ref="elem3" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <!-- No UPA violation if the head element is abstract (it cannot be used in an instance). --> <xs:complexType name="restrictedType3"> <xs:complexContent> <xs:restriction base="basicType3"> <xs:sequence> <xs:element ref="elem4" maxOccurs="unbounded"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/invalid_restrictions2.xsd��������������������0000664�0000000�0000000�00000003266�14211403446�0030264�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for invalid models: UPA violation restricting a substitution group head. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="baseType1"> <xs:sequence> <xs:element name="elem1" /> <xs:element minOccurs="0" name="elem2" /> <xs:choice> <xs:element name="elem3" type="xs:string" /> <xs:element name="elem4" type="xs:string" /> </xs:choice> <xs:element minOccurs="0" name="elem5" /> <xs:element minOccurs="0" name="elem6" type="xs:string" /> <xs:element minOccurs="0" name="elem7" /> </xs:sequence> </xs:complexType> <xs:complexType name="restrictedType1"> <xs:complexContent> <xs:restriction base="baseType1"> <xs:sequence> <xs:sequence> <xs:element name="elem1" /> <xs:element minOccurs="0" name="elem2" /> <xs:choice> <xs:element name="elem3" type="xs:token" /> <xs:element name="elem4" type="xs:string" /> </xs:choice> <xs:sequence> <xs:element minOccurs="0" name="elem6" type="xs:string" /> </xs:sequence> </xs:sequence> <xs:sequence> <xs:element minOccurs="0" name="elem7" /> </xs:sequence> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/list_types.xml�������������������������������0000664�0000000�0000000�00000000502�14211403446�0026133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8" ?> <values xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="list_types.xsd"> <list_of_integers> 10 20 30 </list_of_integers> <list_of_integers> 10.0 20 30 </list_of_integers> <list_of_integers> hello </list_of_integers> </values>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/derivations/list_types.xsd�������������������������������0000664�0000000�0000000�00000001243�14211403446�0026134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for list types derivations. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name='listOfIntegers'> <xs:list itemType='xs:integer'/> </xs:simpleType> <!-- Not allowed derivation: itemType can be only atomic or atomic unions. --> <xs:simpleType name='listOfListOfIntegers'> <xs:list itemType='listOfIntegers'/> </xs:simpleType> <xs:element name="values"> <xs:complexType> <xs:sequence> <xs:element name="list_of_integers" type="listOfIntegers" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/elements/������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022502�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/elements/test_alternatives-1.xml�������������������������0000664�0000000�0000000�00000000232�14211403446�0027117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<value xmlns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./type_alternatives.xsd" choice="bool">true</value> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/elements/type_alternatives-no-ns.xsd���������������������0000664�0000000�0000000�00000002717�14211403446�0030023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- XSD 1.1 schema example with defaultAttributes --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="value" type="node-type"> <xs:alternative test="@choice='int'" type="int-node"/> <xs:alternative test="@choice='float'" type="float-node"/> <xs:alternative test="@choice='bool'" type="bool-node"/> </xs:element> <xs:complexType name="node-type" mixed="true"> <xs:attribute name="choice" type="xs:string"/> </xs:complexType> <xs:complexType name="int-node"> <xs:simpleContent> <xs:restriction base="node-type"> <xs:simpleType> <xs:restriction base="xs:int"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> <xs:complexType name="float-node"> <xs:simpleContent> <xs:restriction base="node-type"> <xs:simpleType> <xs:restriction base="xs:float"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> <xs:complexType name="bool-node"> <xs:simpleContent> <xs:restriction base="node-type"> <xs:simpleType> <xs:restriction base="xs:boolean"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:schema> �������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/elements/type_alternatives.xsd���������������������������0000664�0000000�0000000�00000003007�14211403446�0026764�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- XSD 1.1 schema example with defaultAttributes --> <xs:schema xmlns:ns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns"> <xs:element name="value" type="ns:node-type"> <xs:alternative test="@choice='int'" type="ns:int-node"/> <xs:alternative test="@choice='float'" type="ns:float-node"/> <xs:alternative test="@choice='bool'" type="ns:bool-node"/> </xs:element> <xs:complexType name="node-type" mixed="true"> <xs:attribute name="choice" type="xs:string"/> </xs:complexType> <xs:complexType name="int-node"> <xs:simpleContent> <xs:restriction base="ns:node-type"> <xs:simpleType> <xs:restriction base="xs:int"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> <xs:complexType name="float-node"> <xs:simpleContent> <xs:restriction base="ns:node-type"> <xs:simpleType> <xs:restriction base="xs:float"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> <xs:complexType name="bool-node"> <xs:simpleContent> <xs:restriction base="ns:node-type"> <xs:simpleType> <xs:restriction base="xs:boolean"/> </xs:simpleType> </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/��������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022151�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/billion_laughs_model.xsd��������������������������0000664�0000000�0000000�00000012027�14211403446�0027046�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- Billion laughs test for group expansion (ref. issue #59). --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:group name="LOL1"> <xs:sequence> <xs:element name="lol1" /> <xs:element name="lol2" /> </xs:sequence> </xs:group> <xs:group name="LOL2"> <xs:sequence> <xs:group ref="LOL1" /> <xs:group ref="LOL1" /> </xs:sequence> </xs:group> <xs:group name="LOL3"> <xs:sequence> <xs:group ref="LOL2" /> <xs:group ref="LOL2" /> </xs:sequence> </xs:group> <xs:group name="LOL4"> <xs:sequence> <xs:group ref="LOL3" /> <xs:group ref="LOL3" /> </xs:sequence> </xs:group> <xs:group name="LOL5"> <xs:sequence> <xs:group ref="LOL4" /> <xs:group ref="LOL4" /> </xs:sequence> </xs:group> <xs:group name="LOL6"> <xs:sequence> <xs:group ref="LOL5" /> <xs:group ref="LOL5" /> </xs:sequence> </xs:group> <xs:group name="LOL7"> <xs:sequence> <xs:group ref="LOL6" /> <xs:group ref="LOL6" /> </xs:sequence> </xs:group> <xs:group name="LOL8"> <xs:sequence> <xs:group ref="LOL7" /> <xs:group ref="LOL7" /> </xs:sequence> </xs:group> <xs:group name="LOL9"> <xs:sequence> <xs:group ref="LOL8" /> <xs:group ref="LOL8" /> </xs:sequence> </xs:group> <xs:group name="LOL10"> <xs:sequence> <xs:group ref="LOL9" /> <xs:group ref="LOL9" /> </xs:sequence> </xs:group> <xs:group name="LOL11"> <xs:sequence> <xs:group ref="LOL10" /> <xs:group ref="LOL10" /> </xs:sequence> </xs:group> <xs:group name="LOL12"> <xs:sequence> <xs:group ref="LOL11" /> <xs:group ref="LOL11" /> </xs:sequence> </xs:group> <xs:group name="LOL13"> <xs:sequence> <xs:group ref="LOL12" /> <xs:group ref="LOL12" /> </xs:sequence> </xs:group> <xs:group name="LOL14"> <xs:sequence> <xs:group ref="LOL13" /> <xs:group ref="LOL13" /> </xs:sequence> </xs:group> <xs:group name="LOL15"> <xs:sequence> <xs:group ref="LOL14" /> <xs:group ref="LOL14" /> </xs:sequence> </xs:group> <xs:group name="LOL16"> <xs:sequence> <xs:group ref="LOL15" /> <xs:group ref="LOL15" /> </xs:sequence> </xs:group> <xs:group name="LOL17"> <xs:sequence> <xs:group ref="LOL16" /> <xs:group ref="LOL16" /> </xs:sequence> </xs:group> <xs:group name="LOL18"> <xs:sequence> <xs:group ref="LOL17" /> <xs:group ref="LOL17" /> </xs:sequence> </xs:group> <xs:group name="LOL19"> <xs:sequence> <xs:group ref="LOL18" /> <xs:group ref="LOL18" /> </xs:sequence> </xs:group> <xs:group name="LOL20"> <xs:sequence> <xs:group ref="LOL19" /> <xs:group ref="LOL19" /> </xs:sequence> </xs:group> <xs:group name="LOL21"> <xs:sequence> <xs:group ref="LOL20" /> <xs:group ref="LOL20" /> </xs:sequence> </xs:group> <xs:group name="LOL22"> <xs:sequence> <xs:group ref="LOL21" /> <xs:group ref="LOL21" /> </xs:sequence> </xs:group> <xs:group name="LOL23"> <xs:sequence> <xs:group ref="LOL22" /> <xs:group ref="LOL22" /> </xs:sequence> </xs:group> <xs:group name="LOL24"> <xs:sequence> <xs:group ref="LOL23" /> <xs:group ref="LOL23" /> </xs:sequence> </xs:group> <xs:group name="LOL25"> <xs:sequence> <xs:group ref="LOL24" /> <xs:group ref="LOL24" /> </xs:sequence> </xs:group> <xs:group name="LOL26"> <xs:sequence> <xs:group ref="LOL25" /> <xs:group ref="LOL25" /> </xs:sequence> </xs:group> <xs:group name="LOL27"> <xs:sequence> <xs:group ref="LOL26" /> <xs:group ref="LOL26" /> </xs:sequence> </xs:group> <xs:group name="LOL28"> <xs:sequence> <xs:group ref="LOL27" /> <xs:group ref="LOL27" /> </xs:sequence> </xs:group> <xs:group name="LOL29"> <xs:sequence> <xs:group ref="LOL28" /> <xs:group ref="LOL28" /> </xs:sequence> </xs:group> <xs:group name="LOL30"> <xs:sequence> <xs:group ref="LOL29" /> <xs:group ref="LOL29" /> </xs:sequence> </xs:group> <xs:group name="LOL31"> <xs:sequence> <xs:group ref="LOL30" /> <xs:group ref="LOL30" /> </xs:sequence> </xs:group> <xs:group name="LOL32"> <xs:sequence> <xs:group ref="LOL31" /> <xs:group ref="LOL31" /> </xs:sequence> </xs:group> </xs:schema>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/circular_model.xsd��������������������������������0000664�0000000�0000000�00000000455�14211403446�0025661�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for a disallowed circular model (see issue #58). --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:group name="Test-G"> <xs:sequence> <xs:group minOccurs="0" ref="Test-G" /> </xs:sequence> </xs:group> </xs:schema>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/illegal-attributes.xsd����������������������������0000664�0000000�0000000�00000000327�14211403446�0026470�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:annotation ciao="10" xml:lang="en"/> <!-- Illegal attribute --> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/illegal-declarations.xsd��������������������������0000664�0000000�0000000�00000001207�14211403446�0026750�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- A sample schema for testing model validation --> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:anyattribute notNamespace="#all"> <!-- Illegal declaration --> </xs:anyattribute> <!-- Unexpected attribute declarations (should be inside extension tag) --> <xs:complexType name="A" mixed="true"> <xs:simpleContent> <xs:extension base="xs:string"/> </xs:simpleContent> <xs:attribute name="a1" type="xs:short"/> <xs:attribute name="a2" type="xs:negativeInteger"/> </xs:complexType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/illegal-occurs.xsd��������������������������������0000664�0000000�0000000�00000001013�14211403446�0025571�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Illegal minOccurs and maxOccurs declarations --> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="data"> <xs:complexType> <xs:sequence> <xs:element name="comment" type="xs:string" minOccurs="4" maxOccurs="3"/> <xs:element name="name" type="xs:string" minOccurs="4" maxOccurs="2"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/invalid_models1.xsd�������������������������������0000664�0000000�0000000�00000002250�14211403446�0025742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for invalid models: UPA violations with a substitution group head and element. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element type="xs:int" name="a"/> <xs:element type="xs:int" name="b" substitutionGroup="a" /> <xs:complexType name="wrong_type1"> <xs:all> <xs:element ref="a"/> <xs:element ref="b"/> </xs:all> </xs:complexType> <xs:complexType name="wrong_type2"> <xs:all> <xs:element ref="b"/> <xs:element ref="a"/> </xs:all> </xs:complexType> <xs:complexType name="wrong_type3"> <xs:choice> <xs:element ref="a"/> <xs:element ref="b"/> </xs:choice> </xs:complexType> <xs:complexType name="good_type1"> <xs:sequence> <xs:element ref="a"/> <xs:element ref="b"/> </xs:sequence> </xs:complexType> <xs:complexType name="wrong_type4"> <xs:sequence> <xs:element ref="a" maxOccurs="unbounded"/> <xs:element ref="b"/> </xs:sequence> </xs:complexType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/invalid_models2.xsd�������������������������������0000664�0000000�0000000�00000003005�14211403446�0025742�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema test for invalid XSD 1.0 models: UPA violations that involve wildcards and elements. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns" xmlns="http://xmlschema.test/ns" xmlns:other-ns="http://xmlschema.test/other-ns"> <xs:import namespace='http://xmlschema.test/other-ns' schemaLocation='other-ns.xsd'/> <xs:element name="elem0" type="xs:string"/> <!-- UPA violation (any with minOccurs < maxOccurs and ambiguity with elem0 validation) --> <xs:element name='elem1'> <xs:complexType> <xs:sequence> <xs:any namespace='##targetNamespace' minOccurs='0'/> <xs:element ref='elem0'/> </xs:sequence> </xs:complexType> </xs:element> <!-- UPA violation (any and elem0 overlap and choice model) --> <xs:element name='elem2'> <xs:complexType> <xs:choice> <xs:any namespace='##targetNamespace'/> <xs:element ref='elem0'/> </xs:choice> </xs:complexType> </xs:element> <!-- UPA violation (any with minOccurs < maxOccurs and ambiguity with other-ns:elem0) --> <xs:element name='elem3'> <xs:complexType> <xs:sequence> <xs:any namespace='##other' minOccurs='0'/> <xs:element ref='other-ns:elem0'/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/model1.xml����������������������������������������0000664�0000000�0000000�00000000462�14211403446�0024056�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:data xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./models.xsd"> <name>Paul</name> <name>Paul</name> <name>Paul</name> <name>Paul</name> <name>Paul</name> <name>Paul</name> </ns:data> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/models.xsd����������������������������������������0000664�0000000�0000000�00000011272�14211403446�0024157�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- A schema for testing model validation with ModelVisitor class --> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="data"> <xs:complexType> <xs:sequence> <xs:element name="comment" type="xs:string" minOccurs="4" maxOccurs="10"/> <xs:element name="name" type="xs:string" maxOccurs="3"/> </xs:sequence> </xs:complexType> </xs:element> <!-- Groups for model validation tests --> <xs:group name="group1"> <xs:sequence> <xs:element name="elem1" type="xs:string" minOccurs="0" /> <xs:element name="elem2" type="xs:string" minOccurs="0" /> <xs:element name="elem3" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:group> <xs:group name="group2"> <xs:sequence> <xs:element name="elem1" type="xs:string" minOccurs="0" /> <xs:choice minOccurs="0"> <xs:group ref="group1"/> <xs:sequence> <xs:element name="elem2" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> <xs:sequence> <xs:element name="elem3" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> <xs:element name="elem4" /> <xs:sequence> <xs:element name="elem5" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:sequence> <xs:element name="elem6" type="xs:string" maxOccurs="4"/> <xs:element name="elem7" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:sequence> <xs:element name="elem8" type="xs:string" minOccurs="2" maxOccurs="2"/> <xs:element name="elem9" type="xs:string" /> <xs:element name="elem10" type="xs:string" /> </xs:sequence> <xs:element name="elem11" /> </xs:choice> <xs:element name="elem12" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="elem13" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:group name="group3"> <xs:sequence> <xs:element name="elem1" /> <xs:element minOccurs="0" name="elem2" /> <xs:element name="elem3" /> </xs:sequence> </xs:group> <xs:group name="group4"> <xs:all> <xs:element name="elem1" /> <xs:element minOccurs="0" name="elem2" /> <xs:element name="elem3" /> </xs:all> </xs:group> <xs:group name="group5"> <xs:sequence> <xs:sequence> <xs:element name="elem1" /> <xs:element name="elem2" /> <xs:element name="elem3" /> <xs:element name="elem4" /> <xs:element name="elem5" /> </xs:sequence> <xs:sequence> <xs:choice> <xs:element name="elem6" /> <xs:element name="elem7" /> </xs:choice> <xs:element minOccurs="0" name="elem8" /> <xs:element minOccurs="0" name="elem9" /> </xs:sequence> </xs:sequence> </xs:group> <xs:group name="group6"> <xs:choice> <xs:sequence> <xs:element name="elem1" type="xs:string"/> <xs:element name="elem2" type="xs:string" /> </xs:sequence> <xs:sequence> <xs:element name="elem2" type="xs:string" /> <xs:element name="elem4" type="xs:string" /> </xs:sequence> </xs:choice> </xs:group> <xs:group name="group7"> <xs:sequence> <xs:element name="elem1" type="xs:string"/> <xs:element name="elem2" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:group> <xs:complexType name="complexType7"> <xs:group ref="group7" /> </xs:complexType> <xs:complexType name="complexType7_emptiable"> <xs:group ref="group7" minOccurs="0"/> </xs:complexType> <xs:group name="group8"> <xs:sequence> <xs:sequence> <xs:element name="elem1" maxOccurs="unbounded"/> <xs:element name="elem2" minOccurs="0"/> <xs:element name="elem3" minOccurs="0"/> <xs:element name="elem4" minOccurs="0"/> </xs:sequence> <xs:sequence/> </xs:sequence> </xs:group> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/other-ns.xsd��������������������������������������0000664�0000000�0000000�00000000315�14211403446�0024427�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/other-ns"> <xs:element name="elem0" type="xs:string"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/recursive-groups.xsd������������������������������0000664�0000000�0000000�00000001370�14211403446�0026216�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="A" type="xs:string"/> <xs:element name="B" type="xs:string"/> <!-- Circularity between two groups --> <xs:group name="group1"> <xs:sequence> <xs:element ref="A"/> <xs:group ref="group2"/> </xs:sequence> </xs:group> <xs:group name="group2"> <xs:sequence> <xs:element ref="B"/> <xs:group ref="group1"/> </xs:sequence> </xs:group> <!-- Self circularity case--> <xs:group name="groupC"> <xs:sequence> <xs:element ref="A"/> <xs:group ref="groupC"/> </xs:sequence> </xs:group> </xs:schema>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/models/valid_model1.xsd����������������������������������0000664�0000000�0000000�00000002046�14211403446�0025233�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- A valid schema model (related to issue #182). --> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="elem1" type="xs:string" /> <xs:element name="elem2" type="xs:string" /> <xs:element name="elem3" type="xs:string" /> <xs:element name="elem4" type="xs:string" /> <xs:complexType name="type1"> <xs:sequence> <xs:element ref="elem1" maxOccurs="10" /> <xs:choice> <xs:sequence> <xs:choice> <xs:element ref="elem2" /> <xs:element ref="elem3" /> </xs:choice> </xs:sequence> <xs:sequence> <xs:element ref="elem4" /> <xs:choice> <xs:element ref="elem2" minOccurs="0" /> <xs:element ref="elem3" minOccurs="0" /> </xs:choice> </xs:sequence> </xs:choice> </xs:sequence> </xs:complexType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/����������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0023005�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/chameleon1.xsd��������������������������������0000664�0000000�0000000�00000000227�14211403446�0025542�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/chameleon2.xsd��������������������������������0000664�0000000�0000000�00000000315�14211403446�0025541�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="ns:rootType"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/chameleon3.xsd��������������������������������0000664�0000000�0000000�00000000420�14211403446�0025537�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:import namespace="http://example.com/xmlschema/namespaces"/> <xs:element name="root" type="ns:rootType"/> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/default_ns_invalid.xsd������������������������0000664�0000000�0000000�00000000663�14211403446�0027364�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An invalid usage of the default namespace: it isn't mapped to targetNamespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> �����������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/default_ns_valid1.xsd�������������������������0000664�0000000�0000000�00000000741�14211403446�0027113�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid usage of the default namespace: mapped by an explicit declaration. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> �������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/default_ns_valid2.xsd�������������������������0000664�0000000�0000000�00000000567�14211403446�0027122�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid usage of the default namespace: for default is mapped to no namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case1.xsd������������������������������0000664�0000000�0000000�00000001066�14211403446�0026034�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An invalid import case: the default namespace is mapped to targetNamespace but the imported chameleon schema still maps default namespace to no namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:import schemaLocation="chameleon1.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case2.xsd������������������������������0000664�0000000�0000000�00000001066�14211403446�0026035�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An invalid import case: the default namespace is mapped to targetNamespace but the imported chameleon schema still maps default namespace to no namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:import schemaLocation="chameleon2.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case3.xsd������������������������������0000664�0000000�0000000�00000000664�14211403446�0026041�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid import case: imported chameleon schema imports the target namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:import schemaLocation="chameleon3.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ����������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case4-1.xml����������������������������0000664�0000000�0000000�00000000361�14211403446�0026174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <b:rootB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/xmlschema/ns-A import-case4a.xsd" xmlns:b="http://example.com/xmlschema/ns-B" /> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case4-2.xml����������������������������0000664�0000000�0000000�00000000474�14211403446�0026202�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <a:rootA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/xmlschema/ns-B import-case4b.xsd" xmlns:a="http://example.com/xmlschema/ns-A" xmlns:b="http://example.com/xmlschema/ns-B"> <b:rootB/> </a:rootA>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case4a.xsd�����������������������������0000664�0000000�0000000�00000001320�14211403446�0026171�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An valid import case: two namespaces, each one with a global element that can be used as valid root element for XML instances. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:a="http://example.com/xmlschema/ns-A" xmlns:b="http://example.com/xmlschema/ns-B" targetNamespace="http://example.com/xmlschema/ns-A" elementFormDefault="qualified"> <xs:import schemaLocation="import-case4b.xsd" namespace="http://example.com/xmlschema/ns-B"/> <xs:element name="rootA" type="a:rootType"/> <xs:complexType name="rootType"> <xs:sequence> <xs:element ref="b:rootB" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/import-case4b.xsd�����������������������������0000664�0000000�0000000�00000001320�14211403446�0026172�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An valid import case: two namespaces, each one with a global element that can be used as valid root element for XML instances. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:a="http://example.com/xmlschema/ns-A" xmlns:b="http://example.com/xmlschema/ns-B" targetNamespace="http://example.com/xmlschema/ns-B" elementFormDefault="qualified"> <xs:import schemaLocation="import-case4a.xsd" namespace="http://example.com/xmlschema/ns-A"/> <xs:element name="rootB" type="b:rootType"/> <xs:complexType name="rootType"> <xs:sequence> <xs:element ref="a:rootA" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case1.xsd�����������������������������0000664�0000000�0000000�00000000770�14211403446�0026146�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid include of a chameleon schema using an explicit declaration of the default namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="chameleon1.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ��������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case1bis.xsd��������������������������0000664�0000000�0000000�00000000663�14211403446�0026645�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid include using the default namespace, including a chameleon schema. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="chameleon1.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> �����������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case2.xsd�����������������������������0000664�0000000�0000000�00000001116�14211403446�0026142�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid include of a chameleon schema using an explicit declaration of the default namespace. In this case the chameleon schema uses another prefix for the same target namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="chameleon2.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case2bis.xsd��������������������������0000664�0000000�0000000�00000001035�14211403446�0026640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- A valid include of a chameleon schema using an implicit declaration of the default namespace. In this case the chameleon schema uses another prefix for the same target namespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="chameleon2.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case3.xsd�����������������������������0000664�0000000�0000000�00000001004�14211403446�0026137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An valid include from a schema with a targetNamespace, with the default namespace explicitly mapped. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="included3-valid.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case4.xsd�����������������������������0000664�0000000�0000000�00000000752�14211403446�0026151�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An invalid include: including a schema with a different targetNamespace. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="included4-invalid.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ����������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case5.xsd�����������������������������0000664�0000000�0000000�00000001010�14211403446�0026136�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An valid include from a schema with a targetNamespace, with the default namespace explicitly mapped. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:nsx="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="included5-valid.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/include-case6.xsd�����������������������������0000664�0000000�0000000�00000000763�14211403446�0026155�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- An invalid include from a schema with a targetNamespace not mapped to any prefix. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:include schemaLocation="included6-invalid.xsd"/> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema> �������������xmlschema-1.10.0/tests/test_cases/features/namespaces/included3-valid.xsd���������������������������0000664�0000000�0000000�00000000405�14211403446�0026473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/included4-invalid.xsd�������������������������0000664�0000000�0000000�00000000401�14211403446�0027017�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/xmlschema/elements" targetNamespace="http://example.com/xmlschema/elements" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/included5-valid.xsd���������������������������0000664�0000000�0000000�00000000415�14211403446�0026476�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:nsy="http://example.com/xmlschema/namespaces" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="nsy:rootType"/> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/namespaces/included6-invalid.xsd�������������������������0000664�0000000�0000000�00000000323�14211403446�0027024�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/xmlschema/namespaces" elementFormDefault="qualified"> <xs:element name="root" type="rootType"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/patterns/������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022526�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/patterns/patterns.xml������������������������������������0000664�0000000�0000000�00000001501�14211403446�0025105�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <ns:patterns xmlns:ns="ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns ./patterns.xsd"> <ISBN>b0123456789012</ISBN> <ISBN>b01234567890123</ISBN> <!--Error--> <ISBN>b0123456789012</ISBN> <!--Error: duplicated key --> <ZipCode>55555</ZipCode> <ZipCode>I-55555</ZipCode> <!--Error--> <ZipCode>55555-5555</ZipCode> <BasicString>facade</BasicString> <BasicString>façade</BasicString> <!--Error--> <LatinString>façade</LatinString> <Prefix>cc</Prefix> <!--Error--> <Prefix>cc: dd:@#!%</Prefix> <!--Error--> <Timestamp>2015-12-31T13:32:26-02:00</Timestamp> <Timestamp>2015-12-31T13:32:26+02:00</Timestamp> <Digits>5067746900909</Digits> <Word>abc</Word> <NoWord>.</NoWord> </ns:patterns> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/patterns/patterns.xsd������������������������������������0000664�0000000�0000000�00000006314�14211403446�0025112�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns" > <xs:element name="patterns"> <xs:complexType> <xs:sequence> <xs:element name="ISBN" type="ISBNType" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="ZipCode" type="better-us-zipcode" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="BasicString" type="basic-latin-string" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="LatinString" type="latin-1-string" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="Prefix" type="prefix-name" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="Timestamp" type="TimestampType" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="Digits" type="DigitsType" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="Word" type="Word5Type" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="NoWord" type="NotWord5Type" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:simpleType name="ISBNType"> <xs:restriction base="xs:ID"> <xs:pattern value="b\d{13}"/> </xs:restriction> </xs:simpleType> <xs:simpleType name='better-us-zipcode'> <xs:restriction base='xs:string'> <xs:pattern value='[0-9]{5}(-[0-9]{4})?'/> </xs:restriction> </xs:simpleType> <xs:simpleType name="basic-latin-string"> <xs:restriction base="xs:string"> <xs:pattern value="\p{IsBasicLatin}*"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="latin-1-string"> <xs:restriction base="xs:string"> <xs:pattern value="[\p{IsBasicLatin}\p{IsLatin-1Supplement}]*"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="prefix-name"> <xs:restriction base="xs:Name"> <xs:pattern value="[\i-[:]][\c-[:]]*: [\i-[:]][\c-[:]]+:.+" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="TOKEN"> <xs:restriction base="xs:token"> <xs:pattern value="(\p{L}|\p{N}|\p{P}|\p{S})+"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="TimestampType"> <xs:restriction base="xs:string"> <xs:pattern value=".+T.+(Z|[+-].+)"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="DigitsType"> <xs:restriction base="xs:string"> <xs:pattern value="[\S' ']{1,50}"/> </xs:restriction> </xs:simpleType> <!-- Issue 079 --> <xs:simpleType name="issue079Type"> <xs:restriction base="xs:string"> <xs:pattern value="[^\n\t]+"/> </xs:restriction> </xs:simpleType> <!-- Pull Request 114 --> <xs:simpleType name="Word5Type"> <xs:restriction base="xs:string"> <xs:pattern value='[\w]{0,5}'/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NotWord5Type"> <xs:restriction base="xs:string"> <xs:pattern value='[\W]{0,5}'/> </xs:restriction> </xs:simpleType> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/����������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0021637�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example3.wsdl��������������������������������0000664�0000000�0000000�00000004053�14211403446�0025445�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Original example #3 from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e Thi version contains a typo in <binding> definition --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="SubscribeToQuotes"> <part name="body" element="xsd1:SubscribeToQuotes"/> <part name="subscribeheader" element="xsd1:SubscriptionHeader"/> </message> <portType name="StockQuotePortType"> <operation name="SubscribeToQuotes"> <input message="tns:SubscribeToQuotes"/> </operation> </portType> <binding name="StockQuoteSoap" type="tns:StockQuotePortType"> <soap:binding style="document" transport="http://example.com/smtp"/> <operation name="SubscribeToQuotes"> <input message="tns:SubscribeToQuotes"> <!-- attribute 'message' not allowed --> <soap:body parts="body" use="literal"/> <soap:header message="tns:SubscribeToQuotes" part="subscribeheader" use="literal"/> </input> </operation> </binding> <service name="StockQuoteService"> <port name="StockQuotePort" binding="tns:StockQuoteSoap"> <soap:address location="mailto:subscribe@example.com"/> </port> </service> <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="SubscribeToQuotes"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> <element name="SubscriptionHeader" type="anyURI"/> </schema> </types> </definitions>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example3_valid.wsdl��������������������������0000664�0000000�0000000�00000003642�14211403446�0026627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Example #3 from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="SubscribeToQuotes"> <part name="body" element="xsd1:SubscribeToQuotes"/> <part name="subscribeheader" element="xsd1:SubscriptionHeader"/> </message> <portType name="StockQuotePortType"> <operation name="SubscribeToQuotes"> <input message="tns:SubscribeToQuotes"/> </operation> </portType> <binding name="StockQuoteSoap" type="tns:StockQuotePortType"> <soap:binding style="document" transport="http://example.com/smtp"/> <operation name="SubscribeToQuotes"> <input> <soap:body parts="body" use="literal"/> <soap:header message="tns:SubscribeToQuotes" part="subscribeheader" use="literal"/> </input> </operation> </binding> <service name="StockQuoteService"> <port name="StockQuotePort" binding="tns:StockQuoteSoap"> <soap:address location="mailto:subscribe@example.com"/> </port> </service> <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="SubscribeToQuotes"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> <element name="SubscriptionHeader" type="anyURI"/> </schema> </types> </definitions>����������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example4.wsdl��������������������������������0000664�0000000�0000000�00000004124�14211403446�0025445�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Original example #4 from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e Contains a typo with an invalid character data in /binding. --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="GetTradePriceInput"> <part name="tickerSymbol" element="xsd:string"/> <part name="time" element="xsd:timeInstant"/> </message> <message name="GetTradePriceOutput"> <part name="result" type="xsd:float"/> </message> <portType name="StockQuotePortType"> <operation name="GetTradePrice"> <input message="tns:GetTradePriceInput"/> <output message="tns:GetTradePriceOutput"/> </operation> </portType> <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetTradePrice"> <soap:operation soapAction="http://example.com/GetTradePrice"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation>> <!-- '>' is not allowed --> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example4_valid.wsdl��������������������������0000664�0000000�0000000�00000003652�14211403446�0026631�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Example #4 from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <message name="GetTradePriceInput"> <part name="tickerSymbol" type="xsd:string"/> <part name="time" type="xsd:time"/> </message> <message name="GetTradePriceOutput"> <part name="result" type="xsd:float"/> </message> <portType name="StockQuotePortType"> <operation name="GetTradePrice"> <input message="tns:GetTradePriceInput"/> <output message="tns:GetTradePriceOutput"/> </operation> </portType> <binding name="StockQuoteBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetTradePrice"> <soap:operation soapAction="http://example.com/GetTradePrice"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>��������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example5.wsdl��������������������������������0000664�0000000�0000000�00000005664�14211403446�0025460�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Original Example from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e Undeclared namespace in /types and invalid character data. --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://example.com/stockquote/schema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="TimePeriod"> <all> <element name="startTime" type="xsd:time"/> <element name="endTime" type="xsd:time"/> </all> </complexType> <complexType name="ArrayOfFloat"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:float[]"/> </restriction> </complexContent> </complexType> </schema> </types> <message name="GetTradePricesInput"> <part name="tickerSymbol" element="xsd:string"/> <part name="timePeriod" element="xsd1:TimePeriod"/> </message> <message name="GetTradePricesOutput"> <part name="result" type="xsd1:ArrayOfFloat"/> <part name="frequency" type="xsd:float"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice" parameterOrder="tickerSymbol timePeriod frequency"> <input message="tns:GetTradePricesInput"/> <output message="tns:GetTradePricesOutput"/> </operation> </portType> <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetTradePrices"> <soap:operation soapAction="http://example.com/GetTradePrices"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation>> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>����������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example5_valid.wsdl��������������������������0000664�0000000�0000000�00000006133�14211403446�0026627�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Example from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://example.com/stockquote/schema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <!-- use fallback locations for finding soap-encoding.xsd schema --> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="TimePeriod"> <all> <element name="startTime" type="xsd:time"/> <element name="endTime" type="xsd:time"/> </all> </complexType> <complexType name="ArrayOfFloat"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:float[]"/> </restriction> </complexContent> </complexType> </schema> </types> <message name="GetTradePricesInput"> <part name="tickerSymbol" type="xsd:string"/> <part name="timePeriod" type="xsd1:TimePeriod"/> </message> <message name="GetTradePricesOutput"> <part name="result" type="xsd1:ArrayOfFloat"/> <part name="frequency" type="xsd:float"/> </message> <portType name="StockQuotePortType"> <operation name="GetTradePrices" parameterOrder="tickerSymbol timePeriod frequency"> <input message="tns:GetTradePricesInput"/> <output message="tns:GetTradePricesOutput"/> </operation> </portType> <binding name="StockQuoteBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetTradePrices"> <soap:operation soapAction="http://example.com/GetTradePrices"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/features/wsdl/wsdl11_example5_with_fault.wsdl���������������������0000664�0000000�0000000�00000006526�14211403446�0027704�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Example from WSDL 1.1 definition with SOAP 1.1 bindings: href: https://www.w3.org/TR/2001/NOTE-wsdl-20010315#_soap-e --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://example.com/stockquote/schema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote/schema" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <!-- use fallback locations for finding soap-encoding.xsd schema --> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="TimePeriod"> <all> <element name="startTime" type="xsd:time"/> <element name="endTime" type="xsd:time"/> </all> </complexType> <complexType name="ArrayOfFloat"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:float[]"/> </restriction> </complexContent> </complexType> </schema> </types> <message name="GetTradePricesInput"> <part name="tickerSymbol" type="xsd:string"/> <part name="timePeriod" type="xsd1:TimePeriod"/> </message> <message name="GetTradePricesOutput"> <part name="result" type="xsd1:ArrayOfFloat"/> <part name="frequency" type="xsd:float"/> </message> <message name="FaultMessage"> <part name="fault" type="xsd:string"/> </message> <portType name="StockQuotePortType"> <operation name="GetTradePrices" parameterOrder="tickerSymbol timePeriod frequency"> <input message="tns:GetTradePricesInput"/> <output message="tns:GetTradePricesOutput"/> <fault name="fault" message="tns:FaultMessage"/> </operation> </portType> <binding name="StockQuoteBinding" type="tns:StockQuotePortType"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetTradePrices"> <soap:operation soapAction="http://example.com/GetTradePrices"/> <input> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <soap:body use="encoded" namespace="http://example.com/stockquote" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> <fault name="fault"> <soap:fault name="fault"/> </fault> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/�����������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020363�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_008/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022102�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_008/issue_008.xml������������������������������������0000664�0000000�0000000�00000000374�14211403446�0024347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_008.xsd"> <empno>a</empno> <designation>b</designation> <name>c</name> <age>1</age> </root>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_008/issue_008.xsd������������������������������������0000664�0000000�0000000�00000001025�14211403446�0024337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="root"/> <xs:complexType name="root"> <xs:choice> <xs:sequence> <xs:element name="empno" type="xs:string"/> <xs:element name="designation" type="xs:string" /> </xs:sequence> <xs:sequence> <xs:element name="name" type="xs:string" /> <xs:element name="age" type="xs:unsignedByte" /> </xs:sequence> </xs:choice> </xs:complexType> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_009/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_009/issue_009.xsd������������������������������������0000664�0000000�0000000�00000000457�14211403446�0024351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="root"/> <xs:complexType name="root"> <xs:element name="empno" type="xs:string"/> <xs:element name="age" type="xs:unsignedByte" /> </xs:complexType> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022076�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/issue_013-1.xml����������������������������������0000664�0000000�0000000�00000000272�14211403446�0024472�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <LegalType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_013-1.xsd" _Id="FE">FE</LegalType>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/issue_013-1.xsd����������������������������������0000664�0000000�0000000�00000001333�14211403446�0024467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="ID_TYPE"> <xs:restriction base="xs:token"> <xs:maxLength value="10"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="STRING_30"> <xs:restriction base="xs:string"> <xs:maxLength value="30"/> </xs:restriction> </xs:simpleType> <xs:complexType name="TYPE_ATTR_STRING_30"> <xs:simpleContent> <xs:extension base="STRING_30"> <xs:attribute name="_Id" type="ID_TYPE" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="LegalType" type="TYPE_ATTR_STRING_30"/> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/issue_013-2.xml����������������������������������0000664�0000000�0000000�00000000353�14211403446�0024473�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <LegalType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_013-1.xsd" _Id="FE"> This is a string with more than 30 characters </LegalType>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/issue_013.xml������������������������������������0000664�0000000�0000000�00000000270�14211403446�0024332�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <LegalType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_013.xsd" _Id="FE">FE</LegalType>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_013/issue_013.xsd������������������������������������0000664�0000000�0000000�00000001441�14211403446�0024331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="SecIdType"> <xs:restriction base="xs:token"> <xs:maxLength value="10"/> </xs:restriction> </xs:simpleType> <xs:complexType name="SecIdAttrType"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="_Id" type="SecIdType" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="LegalType"> <xs:complexType> <xs:simpleContent> <xs:restriction base="SecIdAttrType"> <xs:maxLength value="30"/> </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:element> </xs:schema>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_014/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022077�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_014/issue014.xsd�������������������������������������0000664�0000000�0000000�00000001054�14211403446�0024174�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:platformCore="urn:core_2017_1.platform.webservices.netsuite.com" targetNamespace="urn:sales_2017_1.transactions.webservices.netsuite.com" elementFormDefault="qualified"> <xsd:import namespace="urn:core_2017_1.platform.webservices.netsuite.com" schemaLocation="https://webservices.netsuite.com/xsd/platform/v2017_1_0/core.xsd"/> <element name="Opportunity" type="platformCore:RecordRef"/> </xsd:schema>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_018/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_018/issue_018-1.xml����������������������������������0000664�0000000�0000000�00000000301�14211403446�0024475�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./issue_018.xsd"> <node mode="A" value="High"/> <node mode="B" name="Low"/> </root> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_018/issue_018.xsd������������������������������������0000664�0000000�0000000�00000002651�14211403446�0024347�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!--Note: this is an XSD 1.1 schema --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="rootType"/> <xs:element name="node" type="nodeType"> <xs:alternative test="@mode='A'" type="nodeA"/> <xs:alternative test="@mode='B'" type="nodeB"/> </xs:element> <xs:complexType name="rootType"> <xs:sequence> <xs:element ref="node" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="nodeType"> <xs:attribute name="mode" type="allowed-node-types"/> </xs:complexType> <xs:simpleType name="allowed-node-types"> <xs:restriction base="xs:string"> <xs:enumeration value="A"/> <xs:enumeration value="B"/> </xs:restriction> </xs:simpleType> <xs:complexType name="nodeA"> <xs:complexContent> <xs:extension base="nodeType"> <xs:attribute name="value" type="xs:string" use="required"/> <xs:anyAttribute /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="nodeB"> <xs:complexContent> <xs:extension base="nodeType"> <xs:attribute name="name" type="xs:string" use="required"/> <xs:anyAttribute processContents="skip"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema>���������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_022/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022076�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_022/README.md����������������������������������������0000664�0000000�0000000�00000002030�14211403446�0023350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������From [issue #22](https://github.com/brunato/xmlschema/issues/22#issuecomment-345236067). Core of the issue is described as follows: > One thing I noticed is that the to_dict function is not consistent in how it > creates values in the dictionary for sequences. The sequence can already be > anticipated from the .xsd, so I would have expected those values to be within > array structures no matter the number of sequence elements present in the > parent xml element. See xsd in `./xsd_string.xsd`. See xml in `./xml_string_1.xml` and `./xml_string_2.xml`. ```` python import xmlschema xsd_schema = xmlschema.XMLSchema(xsd_string) xml_data_1 = xsd_schema.to_dict(xml_string_1) xml_data_2 = xsd_schema.to_dict(xml_string_2) print(xml_data_1) {'bar': {'@name': 'bar_1', 'subject_name': 'Bar #1'}} print(xml_data_2) {'bar': [{'@name': 'bar_1', 'subject_name': 'Bar #1'}, {'@name': 'bar_2', 'subject_name': 'Bar #2'}]} ```` We would expect the output from each to contain a list; The first a list with one dictionary. ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_022/xml_string_1.xml���������������������������������0000664�0000000�0000000�00000000202�14211403446�0025220�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <foo> <bar name="bar_1"> <subject_name>Bar #1</subject_name> </bar> </foo> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_022/xml_string_2.xml���������������������������������0000664�0000000�0000000�00000000320�14211403446�0025222�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <foo> <bar name="bar_1"> <subject_name>Bar #1</subject_name> </bar> <bar name="bar_2"> <subject_name>Bar #2</subject_name> </bar> </foo> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_022/xsd_string.xsd�����������������������������������0000664�0000000�0000000�00000001232�14211403446�0025000�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="foo" type="Foo" /> <xs:complexType name="Foo"> <xs:sequence minOccurs="1" maxOccurs="unbounded"> <xs:element name="bar" type="Bar" /> </xs:sequence> </xs:complexType> <xs:complexType name="Bar"> <xs:sequence minOccurs="1" maxOccurs="1"> <xs:element name="subject_name" type="xs:string" /> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required" /> </xs:complexType> </xs:schema>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_026/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022102�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_026/issue_026-1.xml����������������������������������0000664�0000000�0000000�00000000345�14211403446�0024503�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_026.xsd"> <bar name="BAR"> <subject_name>Bar</subject_name> </bar> </foo>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_026/issue_026-2.xml����������������������������������0000664�0000000�0000000�00000000340�14211403446�0024477�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_026.xsd"> <bar name="RAB"> <subject_name>Bar</subject_name> </bar> </foo>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_026/issue_026-3.xml����������������������������������0000664�0000000�0000000�00000000325�14211403446�0024503�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_026.xsd"> <bar> <subject_name>Bar</subject_name> </bar> </foo>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_026/issue_026.xsd������������������������������������0000664�0000000�0000000�00000001230�14211403446�0024335�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="foo" type="Foo" /> <xs:complexType name="Foo"> <xs:sequence minOccurs="1" maxOccurs="unbounded"> <xs:element name="bar" type="Bar" /> </xs:sequence> </xs:complexType> <xs:complexType name="Bar"> <xs:sequence minOccurs="1" maxOccurs="1"> <xs:element name="subject_name" type="xs:string" /> </xs:sequence> <xs:attribute name="name" fixed="BAR" use="required" /> </xs:complexType> </xs:schema>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_028/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_028/issue_028-1.xml����������������������������������0000664�0000000�0000000�00000000313�14211403446�0024502�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_028.xsd"> <foo>my_foo</foo> <bar>my_bar</bar> </root>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_028/issue_028-2.xml����������������������������������0000664�0000000�0000000�00000000265�14211403446�0024511�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_028.xsd"> <foo>my_foo</foo> </root>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_028/issue_028.xsd������������������������������������0000664�0000000�0000000�00000000541�14211403446�0024345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="Root" /> <xs:complexType name="Root"> <xs:all> <xs:element name="foo" type="xs:string" /> <xs:element name="bar" type="xs:string" /> </xs:all> </xs:complexType> </xs:schema>���������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_029/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022105�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_029/issue_029-1.xml����������������������������������0000664�0000000�0000000�00000000313�14211403446�0024504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_029.xsd"> <foo>my_foo</foo> <bar>my_bar</bar> </root>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_029/issue_029-2.xml����������������������������������0000664�0000000�0000000�00000000237�14211403446�0024512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_029.xsd"> </root>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_029/issue_029-3.xml����������������������������������0000664�0000000�0000000�00000000265�14211403446�0024514�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_029.xsd"> <foo>my_foo</foo> </root>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_029/issue_029.xsd������������������������������������0000664�0000000�0000000�00000000553�14211403446�0024352�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="Root" /> <xs:complexType name="Root"> <xs:sequence> <xs:element name="foo" type="xs:string" /> <xs:element name="bar" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_035/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022102�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_035/dates.xml����������������������������������������0000664�0000000�0000000�00000001545�14211403446�0023731�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!--file structure> <string></string> <day1/> <day2/> <month1/> <month2/> <year1/> <year2/> <periodicity/> <interim_number/> --> <dates xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="dates.xsd"> <row> <string>2017-01-01</string> <day1>01</day1> <month1>01</month1> <year1>2017</year1> </row> <row> <string>2017-01-01 2017-12-31</string> <day1>01</day1> <day2>31</day2> <month1>01</month1> <month2>12</month2> <year1>2017</year1> <year2>2017</year2> </row> <row> <string>Q4 2017</string> <year1>2017</year1> <periodicity>Q</periodicity> <interim_number>4</interim_number> </row> <row> <string>abrakadabra costam costam 17</string> <abc></abc> </row> </dates>�����������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_035/dates.xsd����������������������������������������0000664�0000000�0000000�00000002071�14211403446�0023722�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="dates"> <xs:complexType> <xs:sequence> <xs:element name="row" minOccurs="1" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="string" type="xs:string"/> <xs:element name="day1" type="xs:int" minOccurs="0" maxOccurs="1"/> <xs:element name="day2" type="xs:int" minOccurs="0" maxOccurs="1"/> <xs:element name="month1" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="month2" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="year1" type="xs:int" minOccurs="0" maxOccurs="1"/> <xs:element name="year2" type="xs:int" minOccurs="0" maxOccurs="1"/> <xs:element name="periodicity" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="interim_number" type="xs:int" minOccurs="0" maxOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_041/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022077�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_041/issue_041.xml������������������������������������0000664�0000000�0000000�00000000367�14211403446�0024343�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <Detail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_041.xsd"> <Name>SomeNameValueThingy</Name> <Value> <Integer>+00000000</Integer> </Value> </Detail>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_041/issue_041.xsd������������������������������������0000664�0000000�0000000�00000001304�14211403446�0024331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Detail" type="my_detail"/> <xs:complexType name="my_detail"> <xs:sequence> <xs:element name="Name" type="xs:string"></xs:element> <xs:element name="Value"> <xs:complexType> <xs:choice> <xs:element name="Boolean" type="xs:boolean" /> <xs:element name="Integer" type="xs:int" /> <xs:element name="Decimal" type="xs:decimal" /> <xs:element name="Code" type="xs:string" /> </xs:choice> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:schema>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_045/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_045/issue_045.xsd������������������������������������0000664�0000000�0000000�00000000423�14211403446�0024342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="PrintableString"> <xs:restriction base="xs:string"> <xs:pattern value="[ '\(\)\+-:=\?A-Za-z]*"/> </xs:restriction> </xs:simpleType> </xs:schema>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_046/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_046/issue_046.xml������������������������������������0000664�0000000�0000000�00000000542�14211403446�0024350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- Test taken from https://www.w3schools.com/xml/schema_complex_mixed.asp --> <letter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_046.xsd"> Dear Mr.<name>John Smith</name>. Your order <orderid>1032</orderid> will be shipped on <shipdate>2001-07-13</shipdate>. </letter>��������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_046/issue_046.xsd������������������������������������0000664�0000000�0000000�00000000643�14211403446�0024350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="letter"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderid" type="xs:positiveInteger"/> <xs:element name="shipdate" type="xs:date"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>���������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_051/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022100�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_051/issue_051.xml������������������������������������0000664�0000000�0000000�00000000513�14211403446�0024336�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <KeyValuePairs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_051.xsd"> <test>root</test> <test2>root</test2> <test3>root</test3> <test4>root</test4> <test5>root</test5> <test6>root</test6> <test7>root</test7> </KeyValuePairs>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_051/issue_051.xsd������������������������������������0000664�0000000�0000000�00000001470�14211403446�0024337�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" > <xs:element name="KeyValuePairs" type="KeyValuePairsType"/> <xs:complexType name="KeyValuePairsType"> <xs:all> <xs:element type="xs:string" name="test2" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test3" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test4" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test5" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test6" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test7" minOccurs="0" maxOccurs="1" /> <xs:element type="xs:string" name="test" minOccurs="1" maxOccurs="1" /> </xs:all> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_073/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_073/issue_073-1.xml����������������������������������0000664�0000000�0000000�00000000507�14211403446�0024507�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <ns:items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns="ns" xsi:schemaLocation="ns issue_073.xsd"> <a1>item1</a1> <a2>item2</a2> <a3>item3</a3> <a4>item3</a4> <a5>item3</a5> <a6>item3</a6> <a7>item3</a7> <a8>item3</a8> </ns:items>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_073/issue_073-2.xml����������������������������������0000664�0000000�0000000�00000000552�14211403446�0024510�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <ns:items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns="ns" xsi:schemaLocation="ns issue_073.xsd"> <a1>item1</a1> <a2>item2</a2> <a3>item3</a3> <a4>item3</a4> <a5>item3</a5> <a6>item3</a6> <something>unknown</something> <a7>item3</a7> <a8>item3</a8> </ns:items>������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_073/issue_073.xsd������������������������������������0000664�0000000�0000000�00000001255�14211403446�0024350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:ns="ns" targetNamespace="ns"> <element name="items" type="ns:sequenceType" /> <complexType name="sequenceType"> <sequence> <element type="string" name="a1" minOccurs="0" /> <element type="string" name="a2" minOccurs="0" /> <element type="string" name="a3" /> <element type="string" name="a4" minOccurs="0" maxOccurs="unbounded" /> <element type="string" name="a5" minOccurs="0" /> <element type="string" name="a6" minOccurs="0" /> <element type="string" name="a7" minOccurs="0" /> <element type="string" name="a8" minOccurs="0" /> </sequence> </complexType> </schema>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_086/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022110�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_086/issue_086-1.xml����������������������������������0000664�0000000�0000000�00000000623�14211403446�0024516�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <foo xmlns='' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_086.xsd"> <header>0</header> <a> <spam>first</spam> </a> <a> <spam>first</spam> </a> <b> <spam>second</spam> </b> <b> <spam>second</spam> </b> <c> <spam>third</spam> </c> <c> <spam>third</spam> </c> </foo>�������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_086/issue_086-2.xml����������������������������������0000664�0000000�0000000�00000000623�14211403446�0024517�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <foo xmlns='' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_086.xsd"> <header>0</header> <b> <spam>second</spam> </b> <b> <spam>second</spam> </b> <c> <spam>third</spam> </c> <c> <spam>third</spam> </c> <a> <spam>first</spam> </a> <a> <spam>first</spam> </a> </foo>�������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_086/issue_086.xsd������������������������������������0000664�0000000�0000000�00000002460�14211403446�0024357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="foo" type="Foo" /> <xs:complexType name="Foo"> <xs:sequence minOccurs="1" maxOccurs="1"> <xs:element name="header" type="Header" /> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="a" type="Bar" /> </xs:sequence> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="b" type="Bar" /> </xs:sequence> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="c" type="Bar" /> </xs:sequence> </xs:choice> </xs:sequence> </xs:complexType> <xs:simpleType name="Header"> <xs:restriction base="xs:nonNegativeInteger" /> </xs:simpleType> <xs:complexType name="Bar"> <xs:all minOccurs="1"> <xs:element name="spam" minOccurs="0" type="Spam" /> </xs:all> </xs:complexType> <xs:simpleType name="Spam"> <xs:restriction base="xs:string" /> </xs:simpleType> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_105/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022100�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_105/issue_105.xsd������������������������������������0000664�0000000�0000000�00000001003�14211403446�0024327�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="project" type="TProject"> <xs:key name="widgetId"> <xs:selector xpath=".//widgets/widget | .//logic/widget"/> <xs:field xpath="@id"/> </xs:key> </xs:element> <xs:complexType name="TProject"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="protocols"/> </xs:choice> </xs:complexType> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_111/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022075�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_111/issue_111.xsd������������������������������������0000664�0000000�0000000�00000001272�14211403446�0024331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:redefine schemaLocation="issue_111_skeleton.xsd"> <xs:complexType name="extendedHeaderDef"> <xs:complexContent> <xs:extension base="extendedHeaderDef"> <xs:attribute name="isAttr2" type="xs:boolean"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:redefine> <xs:element name="rootElement"> <xs:complexType> <xs:sequence> <xs:element name="block1" type="blockDef"/> <xs:element name="optional" type="optionalBlock"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_111/issue_111_skeleton.xsd���������������������������0000664�0000000�0000000�00000001116�14211403446�0026232�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:complexType name="blockDef" abstract="true"> <xs:attribute name="isAttr1" type="xs:boolean"/> </xs:complexType> <xs:complexType name="extendedHeaderDef"> <xs:complexContent> <xs:extension base="blockDef"/> </xs:complexContent> </xs:complexType> <xs:complexType name="optionalBlock"> <xs:sequence> <xs:element name="extendedHeader" type="extendedHeaderDef"/> </xs:sequence> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_115/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022101�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_115/Rotation.xsd�������������������������������������0000664�0000000�0000000�00000001154�14211403446�0024421�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.example.org/Rotation/" targetNamespace="http://www.example.org/Rotation/"> <element name="rotation"> <complexType> <attribute name="roll" type="tns:degree" /> <attribute name="pitch" type="tns:degree" /> <attribute name="yaw" type="tns:degree" /> </complexType> </element> <simpleType name="degree"> <restriction base="float"> <minInclusive value="0" /> <maxInclusive value="360" /> </restriction> </simpleType> </schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_171/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_171/issue_171.xsd������������������������������������0000664�0000000�0000000�00000001027�14211403446�0024343�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <xs:element name="tag"> <xs:complexType> <xs:sequence/> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="abc" type="xs:integer"/> <xs:attribute name="def" type="xs:integer"/> <xs:assert test="(@abc and not(@def)) or (not(@abc) and @def)"/> </xs:complexType> </xs:element> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_171/issue_171b.xsd�����������������������������������0000664�0000000�0000000�00000001104�14211403446�0024501�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <xs:element name="tag"> <xs:complexType> <xs:sequence/> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="abc" type="xs:float"/> <xs:attribute name="def" type="xs:float"/> <xs:assert test="(@abc and not(@def castable as xs:double)) or (not(@abc castable as xs:double) and @def)"/> </xs:complexType> </xs:element> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_171/issue_171c.xsd�����������������������������������0000664�0000000�0000000�00000000770�14211403446�0024512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <xs:element name="tag"> <xs:complexType> <xs:sequence/> <xs:attribute name="name" type="xs:string"/> <xs:attribute name="abc" type="xs:integer"/> <xs:attribute name="def" type="xs:integer"/> <xs:assert test="@abc and @def"/> </xs:complexType> </xs:element> </xs:schema> ��������xmlschema-1.10.0/tests/test_cases/issues/issue_187/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022112�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_187/issue_187_1.xsd����������������������������������0000664�0000000�0000000�00000001232�14211403446�0024577�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- A sample base schema that includes schemas from another directory --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="../../examples/vehicles/cars.xsd"/> <xs:include schemaLocation="../../examples/vehicles/bikes.xsd"/> <xs:element name="vehicles"> <xs:complexType> <xs:sequence> <xs:element ref="vh:cars" /> <xs:element ref="vh:bikes" /> </xs:sequence> </xs:complexType> </xs:element> <xs:attribute type="xs:positiveInteger" name="step"/> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_187/issue_187_2.xsd����������������������������������0000664�0000000�0000000�00000001444�14211403446�0024605�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!-- A sample base schema that includes schemas from a remote source --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles" targetNamespace="http://example.com/vehicles" elementFormDefault="qualified"> <xs:include schemaLocation="https://raw.githubusercontent.com/brunato/xmlschema/master/tests/test_cases/examples/vehicles/cars.xsd"/> <xs:include schemaLocation="https://raw.githubusercontent.com/brunato/xmlschema/master/tests/test_cases/examples/vehicles/bikes.xsd"/> <xs:element name="vehicles"> <xs:complexType> <xs:sequence> <xs:element ref="vh:cars" /> <xs:element ref="vh:bikes" /> </xs:sequence> </xs:complexType> </xs:element> <xs:attribute type="xs:positiveInteger" name="step"/> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_190/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_190/issue_190.xml������������������������������������0000664�0000000�0000000�00000000155�14211403446�0024350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <root> <a> <c>1</c> </a> <b> <e>1</e> <c>1</c> </b> </root> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_190/issue_190.xsd������������������������������������0000664�0000000�0000000�00000001421�14211403446�0024343�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="a" type="type_a"/> <xs:element name="b" type="type_b"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="type_a"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="c"/> <xs:element name="d"/> </xs:choice> </xs:sequence> </xs:complexType> <xs:complexType name="type_b"> <xs:sequence> <xs:element name="e" minOccurs="0" maxOccurs="unbounded"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="c"/> <xs:element name="d"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_200/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022074�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_200/issue_200.xml������������������������������������0000664�0000000�0000000�00000000466�14211403446�0024335�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <na:main xmlns:na="ames" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ames ./issue_200.xsd"> <na:item doc_id="1" ref_id="k1">content_k1</na:item> <na:item doc_id="2" ref_id="k2">content_k2</na:item> </na:main> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_200/issue_200.xsd������������������������������������0000664�0000000�0000000�00000001360�14211403446�0024325�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:na="ames" targetNamespace="ames" elementFormDefault="qualified"> <xs:complexType name="itemtype"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="doc_id" type="xs:int" /> <xs:attribute name="ref_id" type="xs:string" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="maintype"> <xs:sequence> <xs:element name="item" maxOccurs="unbounded" type="na:itemtype" /> </xs:sequence> </xs:complexType> <xs:element name="main" type="na:maintype" /> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_203/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022077�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_203/issue_203.xml������������������������������������0000664�0000000�0000000�00000000304�14211403446�0024332�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <!-- issue_203.xml --> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_203.xsd"> <elem1/> </root> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_203/issue_203.xsd������������������������������������0000664�0000000�0000000�00000001700�14211403446�0024331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <!-- issue_203.xsd - Invalid for XSD 1.0 (restriction items not in base order) --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="restrictedModel"/> <xs:complexType name="baseModel"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="elem1"/> <xs:element name="elem2"/> <xs:element name="elem3"/> <xs:element name="elem4"/> <xs:element name="elem5"/> </xs:choice> </xs:complexType> <xs:complexType name="restrictedModel"> <xs:complexContent> <xs:restriction base="baseModel"> <xs:choice> <xs:element name="elem1"/> <xs:element name="elem5"/> <xs:element name="elem2"/> </xs:choice> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:schema> ����������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_203/issue_203alt.xsd���������������������������������0000664�0000000�0000000�00000001704�14211403446�0025036�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <!-- issue_203alt.xsd - Valid also for XSD 1.0 (restriction items with base order) --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="restrictedModel"/> <xs:complexType name="baseModel"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="elem1"/> <xs:element name="elem2"/> <xs:element name="elem3"/> <xs:element name="elem4"/> <xs:element name="elem5"/> </xs:choice> </xs:complexType> <xs:complexType name="restrictedModel"> <xs:complexContent> <xs:restriction base="baseModel"> <xs:choice> <xs:element name="elem1"/> <xs:element name="elem2"/> <xs:element name="elem5"/> </xs:choice> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:schema> ������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_204/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022100�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_204/issue_204.xsd������������������������������������0000664�0000000�0000000�00000001014�14211403446�0024331�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="rootType" /> <xs:complexType name="rootType"> <xs:sequence> <xs:element name="child1" minOccurs="0" /> <xs:element name="child2" minOccurs="0" /> <xs:element name="child3" /> <xs:element name="child4" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="child5" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_204/issue_204_1.xml����������������������������������0000664�0000000�0000000�00000000254�14211403446�0024560�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8" ?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_204.xsd"> <child3/> </root>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_204/issue_204_2.xml����������������������������������0000664�0000000�0000000�00000000272�14211403446�0024561�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8" ?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_204.xsd"> <child2/> <child5/> </root>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_204/issue_204_3.xml����������������������������������0000664�0000000�0000000�00000000336�14211403446�0024563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8" ?> <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_204.xsd"> <child2/> <unknown><a>1</a><b/></unknown> <child5/> </root>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_208/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022104�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_208/issue_208.xml������������������������������������0000664�0000000�0000000�00000000462�14211403446�0024351�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<dll32-answer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlschema.test/ns" xsi:schemaLocation="http://xmlschema.test/ns issue_208.xsd"> <system> <interface-category active-method="0">low-level-interface-only</interface-category> </system> </dll32-answer>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_208/issue_208.xsd������������������������������������0000664�0000000�0000000�00000002774�14211403446�0024357�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns="http://xmlschema.test/ns" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:simpleType name="interface-categoryType"> <xs:restriction base="xs:token"> <xs:enumeration value="low-level-interface-only"/> <xs:enumeration value="wildcard-readout-only"/> <xs:enumeration value="key-list-readout-only"/> </xs:restriction> </xs:simpleType> <xs:complexType name="data-point-interface-categoryType"> <xs:simpleContent> <xs:extension base="interface-categoryType"/> </xs:simpleContent> </xs:complexType> <xs:element name="dll32-answer"> <xs:complexType> <xs:sequence> <xs:element name="system"> <xs:complexType> <xs:all> <xs:element name="interface-category"> <xs:complexType> <xs:complexContent> <xs:extension base="data-point-interface-categoryType"> <xs:attribute name="active-method"> <xs:simpleType> <xs:restriction base="xs:byte"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:all> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>����xmlschema-1.10.0/tests/test_cases/issues/issue_222/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022100�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_222/issue_222.xml������������������������������������0000664�0000000�0000000�00000000102�14211403446�0024330�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<root> <first>ABCEDF</first> <second>ABCEDF</second> </root> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_222/issue_222.xsd������������������������������������0000664�0000000�0000000�00000001071�14211403446�0024334�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="first" type="xsd:hexBinary" fixed="abcedf" /> <xsd:element name="second" type="enum" /> <xsd:simpleType name="enum"> <xsd:restriction base="xsd:hexBinary"> <xsd:enumeration value="abcedf" /> </xsd:restriction> </xsd:simpleType> <xsd:element name="root"> <xsd:complexType> <xsd:sequence> <xsd:element ref="first" /> <xsd:element ref="second" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_223/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022101�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_223/issue_223.xml������������������������������������0000664�0000000�0000000�00000000056�14211403446�0024342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<CadastralBlock>38:36:000031 </CadastralBlock>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_223/issue_223.xsd������������������������������������0000664�0000000�0000000�00000000610�14211403446�0024334�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="CadastralBlock" type="CadastralBlockType"/> <xs:simpleType name="CadastralBlockType"> <xs:restriction base="xs:string"> <xs:maxLength value="13"/> <xs:minLength value="12"/> <xs:pattern value="\d{2}:\d{2}:\d{6,7}"/> </xs:restriction> </xs:simpleType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022106�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir1/��������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022745�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir1/issue_237.xsd�������������������������������0000664�0000000�0000000�00000000277�14211403446�0025216�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:include schemaLocation="../dir2/issue_237a.xsd"/> <xs:element name="root" type="rootType"/> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir1/stockquoteservice.wsdl����������������������0000664�0000000�0000000�00000002341�14211403446�0027422�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/service" xmlns:tns="http://example.com/stockquote/service" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:defs="http://example.com/stockquote/definitions" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/definitions" location="../dir2/stockquote.wsdl"/> <binding name="StockQuoteBinding" type="defs:StockQuotePortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://example.com/GetLastTradePrice"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir2/��������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022746�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir2/issue_237a.xsd������������������������������0000664�0000000�0000000�00000000215�14211403446�0025350�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:include schemaLocation="./issue_237b.xsd"/> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir2/issue_237b.xsd������������������������������0000664�0000000�0000000�00000000472�14211403446�0025356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="rootType"> <xs:restriction base="xs:string"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> <xs:enumeration value="three"/> </xs:restriction> </xs:simpleType> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir2/stockquote.wsdl�����������������������������0000664�0000000�0000000�00000002021�14211403446�0026035�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- From WSDL 1.1 definition: https://www.w3.org/TR/2001/NOTE-wsdl-20010315 --> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote/definitions" xmlns:tns="http://example.com/stockquote/definitions" xmlns:xsd1="http://example.com/stockquote/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/stockquote/schemas" location="./stockquote.xsd" /> <message name="GetLastTradePriceInput"> <part name="body" element="xsd1:TradePriceRequest"/> </message> <message name="GetLastTradePriceOutput"> <part name="body" element="xsd1:TradePrice"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceInput"/> <output message="tns:GetLastTradePriceOutput"/> </operation> </portType> </definitions>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_237/dir2/stockquote.xsd������������������������������0000664�0000000�0000000�00000001230�14211403446�0025663�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <!-- From WSDL 1.1 definition: https://www.w3.org/TR/2001/NOTE-wsdl-20010315 --> <xs:schema targetNamespace="http://example.com/stockquote/schemas" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="TradePriceRequest"> <xs:complexType> <xs:all> <xs:element name="tickerSymbol" type="xs:string"/> </xs:all> </xs:complexType> </xs:element> <xs:element name="TradePrice"> <xs:complexType> <xs:all> <xs:element name="price" type="xs:float"/> </xs:all> </xs:complexType> </xs:element> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_243/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022103�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_243/issue_243.xml������������������������������������0000664�0000000�0000000�00000000433�14211403446�0024345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <manifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.test.com/XMLSchema/manifest/2021"> <session anonymous="true"> <userId xsi:nil="true"/> <sessionId xsi:nil="true"/> </session> </manifest> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_243/issue_243.xsd������������������������������������0000664�0000000�0000000�00000004017�14211403446�0024345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1" xmlns:am="http://www.test.com/XMLSchema/manifest/2021" targetNamespace="http://www.test.com/XMLSchema/manifest/2021" xmlns="http://www.test.com/XMLSchema/manifest/2021"> <xs:element name="manifest"> <xs:complexType> <xs:sequence> <xs:element name="session"> <xs:complexType> <xs:sequence> <xs:element name="userId" nillable="true"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="1"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="sessionId" nillable="true"> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> <xs:attribute name="anonymous" type="xs:boolean" use="required"> </xs:attribute> <xs:assert test="((@anonymous eq true()) and am:userId[@xsi:nil] and am:sessionId[@xsi:nil]) or ((@anonymous eq false()) and am:userId[node()] and am:sessionId[node()])" /> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_245/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022105�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_245/issue_245-valid.xml������������������������������0000664�0000000�0000000�00000001365�14211403446�0025453�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <assessment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns="http://www.test.com/XMLSchema/data/2021" xsi:schemaLocation="http://www.test.com/XMLSchema/data/2021 issue_245.xsd"> <part xsi:type="ContrastVisionTest"> <screen_elements> <contrast_circles> <circle circle_id="1"/> <circle circle_id="0"/> <circle circle_id="2"/> </contrast_circles> </screen_elements> <events> <circle_pressed circle_id="0"/> <circle_pressed circle_id="1"/> <circle_pressed circle_id="2"/> </events> </part> </assessment> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_245/issue_245.xml������������������������������������0000664�0000000�0000000�00000001365�14211403446�0024356�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <assessment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns="http://www.test.com/XMLSchema/data/2021" xsi:schemaLocation="http://www.test.com/XMLSchema/data/2021 issue_245.xsd"> <part xsi:type="ContrastVisionTest"> <screen_elements> <contrast_circles> <circle circle_id="1"/> <circle circle_id="1"/> <circle circle_id="2"/> </contrast_circles> </screen_elements> <events> <circle_pressed circle_id="0"/> <circle_pressed circle_id="1"/> <circle_pressed circle_id="2"/> </events> </part> </assessment> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_245/issue_245.xsd������������������������������������0000664�0000000�0000000�00000011436�14211403446�0024354�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1" targetNamespace="http://www.test.com/XMLSchema/data/2021" xmlns="http://www.test.com/XMLSchema/data/2021" xmlns:ad="http://www.test.com/XMLSchema/data/2021"> <xs:element name="assessment"> <xs:annotation> <xs:documentation>Data about the performed tests.</xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="part" type="AssessmentPart"> <xs:key name="circle_id_key"> <xs:annotation> <xs:documentation>For ContrastVisionTest. Since all parts are types we can not add keys and keyrefs to them. As such, we add the constraints here.</xs:documentation> </xs:annotation> <xs:selector xpath="ad:screen_elements/ad:contrast_circles/ad:circle"/> <xs:field xpath="@circle_id"/> </xs:key> <xs:keyref name="circle_id_keyref" refer="circle_id_key"> <xs:selector xpath="ad:events/ad:circle_pressed"/> <xs:field xpath="@circle_id"/> </xs:keyref> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType abstract="true" name="AssessmentPart"> <xs:annotation> <xs:documentation>Base type for the assessment element.</xs:documentation> </xs:annotation> </xs:complexType> <xs:complexType abstract="true" name="AssessmentTest"> <xs:annotation> <xs:documentation>Base type for a test.</xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="AssessmentPart"/> </xs:complexContent> </xs:complexType> <xs:complexType name="ContrastVisionTest"> <xs:complexContent> <xs:extension base="AssessmentTest"> <xs:sequence> <xs:element name="screen_elements"> <xs:complexType> <xs:sequence> <xs:element name="contrast_circles"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="3" name="circle" minOccurs="3"> <xs:complexType> <xs:attribute name="circle_id" use="required"> <xs:annotation> <xs:documentation>The id of this circle, used to reference the circle presses.</xs:documentation> </xs:annotation> <xs:simpleType> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> <xs:maxInclusive value="9"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="events"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" minOccurs="0" name="circle_pressed"> <xs:complexType> <xs:attribute name="circle_id" type="xs:integer" use="required"/> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_259/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022112�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_259/issue_259-1.xsd����������������������������������0000664�0000000�0000000�00000004566�14211403446�0024532�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" vc:minVersion="1.1"> <xs:complexType name="ConfigurationType"> <xs:all> <xs:element name="DefaultProt1" type="ProtocolDefault" minOccurs="0" maxOccurs="1"/> <xs:element name="DefaultProt2" type="ProtocolDefault" minOccurs="0" maxOccurs="1"/> <!-- More elements --> <xs:element name="DefaultProt13" type="ProtocolDefault" minOccurs="0" maxOccurs="1"/> <xs:element name="connectionChannel" type="connectionChannel" maxOccurs="1" > <xs:unique name="redChannelNameUniqueness"> <xs:selector xpath="redChannel"/> <xs:field xpath="@name"/> </xs:unique> </xs:element> </xs:all> </xs:complexType> <xs:complexType name="connectionChannel"> <xs:all> <xs:element name="Prot1" type="Protocol" minOccurs="0" maxOccurs="1"/> <xs:element name="Prot2" type="Protocol" minOccurs="0" maxOccurs="1"/> <!-- More elements --> <xs:element name="Prot13" type="Protocol" minOccurs="0" maxOccurs="1"/> <xs:element name="redChannel" type="redChannelType" minOccurs="1" maxOccurs="8"/> </xs:all> <xs:attribute name="name" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:minLength value="1"/> <xs:maxLength value="63"/> <xs:pattern value="([a-zA-Z0-9\._\-])*"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> <xs:element name="Configuration" type="ConfigurationType"> <xs:unique name="connectionChannelNameUniqueness"> <xs:selector xpath="connectionChannel"/> <xs:field xpath="@name"/> </xs:unique> </xs:element> <xs:complexType name="redChannelType"> <xs:attribute name="name" use="required" type="xs:string"/> </xs:complexType> <xs:complexType name="ProtocolDefault"> <xs:attribute name="interfaceIdentifier" use="optional" type="xs:unsignedByte"/> <xs:attribute name="outgoingDirectionIdentifier" use="optional" type="xs:unsignedByte"/> </xs:complexType> <xs:complexType name="Protocol"> <xs:attribute name="interfaceIdentifier" use="optional" type="xs:unsignedByte"/> <xs:attribute name="outgoingDirectionIdentifier" use="optional" type="xs:unsignedByte"/> </xs:complexType> </xs:schema>������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_259/issue_259-2.xsd����������������������������������0000664�0000000�0000000�00000002630�14211403446�0024521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" vc:minVersion="1.1"> <xs:redefine schemaLocation="issue_259-1.xsd"> <xs:complexType name="ConfigurationType"> <xs:complexContent> <xs:extension base="ConfigurationType"> <xs:all> <xs:element name="MyProtDefault" type="CustomProtocolDefault" minOccurs="0" maxOccurs="1"/> </xs:all> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="redChannelType"> <xs:complexContent> <xs:extension base="redChannelType"> <xs:all> <xs:element name="MyProt" type="CustomProtocol" minOccurs="0" maxOccurs="1"/> </xs:all> </xs:extension> </xs:complexContent> </xs:complexType> </xs:redefine> <xs:complexType name="CustomProtocolDefault"> <xs:attribute name="interfaceIdentifier" use="optional" type="xs:unsignedByte"/> <xs:attribute name="outgoingDirectionIdentifier" use="optional" type="xs:unsignedByte"/> </xs:complexType> <xs:complexType name="CustomProtocol"> <xs:attribute name="interfaceIdentifier" use="optional" type="xs:unsignedByte"/> <xs:attribute name="outgoingDirectionIdentifier" use="optional" type="xs:unsignedByte"/> </xs:complexType> </xs:schema>��������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_265/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022107�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_265/issue_265-1.xsd����������������������������������0000664�0000000�0000000�00000006617�14211403446�0024523�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="studentInfoHuelle" abstract="true"/> <xs:complexType name="studentInfoMinimal"> <xs:complexContent> <xs:extension base="studentInfoHuelle"> <xs:sequence> <xs:element name="vorname" type="sbtTextNotEmpty" minOccurs="1"/> <xs:element name="nachname" type="sbtTextNotEmpty" minOccurs="1"/> <xs:element name="geburtsdatum" type="xs:date" minOccurs="1"/> <xs:element name="geschlecht" type="geschlechtTyp" minOccurs="1"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="studentInfoBasis"> <xs:complexContent> <xs:extension base="studentInfoMinimal"> <xs:sequence> <xs:element name="staatsbuergerschaft" type="staatTyp" minOccurs="0"/> <xs:element name="akadgrad" type="akadTyp" minOccurs="0"/> <xs:element name="akadnach" type="akadTyp" minOccurs="0"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="studentInfoExtended"> <xs:complexContent> <xs:extension base="studentInfoBasis"> <xs:sequence> <xs:element name="bpk" type="bpkTyp" minOccurs="0"/> <xs:element name="svnr" type="svnrTyp" minOccurs="0"/> <xs:element name="ekz" type="ekzTyp" minOccurs="0"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="studentInfoBasisAdressen"> <xs:complexContent> <xs:extension base="studentInfoExtended"> <xs:sequence> <xs:element name="adressen" type="adressenListe"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="UniStudentInfo"> <xs:complexContent> <xs:extension base="studentInfoBasisAdressen"> <xs:sequence> <xs:element name="studierendenkey" type="Studierendenkey" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="FullStudentInfo"> <xs:complexContent> <xs:extension base="UniStudentInfo"> <xs:sequence> <xs:element name="studienliste" type="studienliste"/> <xs:element name="studienbeitrag" type="KontostandUniInfo"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <!-- Dummy simple types for validating the issue's case --> <xs:simpleType name="sbtTextNotEmpty"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="geschlechtTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="staatTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="akadTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="bpkTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="svnrTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="ekzTyp"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="adressenListe"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Studierendenkey"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="studienliste"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="KontostandUniInfo"> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:schema>�����������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_265/issue_265-2-invalid.xsd��������������������������0000664�0000000�0000000�00000002603�14211403446�0026137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:redefine schemaLocation="issue_265-1.xsd"> <xs:complexType name="FullStudentInfo"> <xs:complexContent> <xs:restriction base="FullStudentInfo"> <xs:sequence> <xs:element name="vorname" type="sbtTextNotEmpty" minOccurs="1"/> <xs:element name="nachname" type="sbtTextNotEmpty" minOccurs="1"/> <xs:element name="geburtsdatum" type="xs:date" minOccurs="1"/> <xs:element name="geschlecht" type="geschlechtTyp" minOccurs="1"/> <xs:element name="staatsbuergerschaft" type="staatTyp" minOccurs="0"/> <xs:element name="akadgrad" type="akadTyp" minOccurs="0"/> <xs:element name="akadnach" type="akadTyp" minOccurs="0"/> <xs:element name="bpk" type="bpkTyp" minOccurs="0"/> <xs:element name="svnr" type="svnrTyp" minOccurs="0"/> <xs:element name="ekz" type="ekzTyp" minOccurs="0"/> <xs:element name="adressen" type="adressenListe"/> <xs:element name="studierendenkey" type="Studierendenkey" minOccurs="1" maxOccurs="1"/> <xs:element name="studienbeitrag" type="KontostandUniInfo"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:redefine> </xs:schema>�����������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_265/issue_265-2-override.xsd�������������������������0000664�0000000�0000000�00000000706�14211403446�0026332�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:override schemaLocation="issue_265-1.xsd"> <xs:complexType name="FullStudentInfo"> <xs:complexContent> <xs:extension base="UniStudentInfo"> <xs:sequence> <xs:element name="studienbeitrag" type="KontostandUniInfo" minOccurs="0"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:override> </xs:schema>����������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022110�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266-1.xml����������������������������������0000664�0000000�0000000�00000000236�14211403446�0024516�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<TestField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_266-1.xsd" testattribute="foo" /> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266-1.xsd����������������������������������0000664�0000000�0000000�00000001032�14211403446�0024507�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xsd:element name="TestField" type="TestFieldType"> <xsd:annotation> <xsd:documentation> <h:div xmlns:h="http://www.w3.org/1999/xhtml"> <h:h3>Some documentation</h:h3> </h:div> </xsd:documentation> </xsd:annotation> </xsd:element> <xsd:complexType name="TestFieldType"> <xsd:attribute name="testattribute" use="optional" type="xsd:string"/> </xsd:complexType> </xsd:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266-2.xml����������������������������������0000664�0000000�0000000�00000000236�14211403446�0024517�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<TestField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="issue_266-2.xsd" testattribute="foo" /> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266-2.xsd����������������������������������0000664�0000000�0000000�00000001020�14211403446�0024505�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xsd:element name="TestField" type="TestFieldType"> <xsd:annotation> <xsd:documentation> <div xmlns="http://www.w3.org/1999/xhtml"> <h3>Some documentation</h3> </div> </xsd:documentation> </xsd:annotation> </xsd:element> <xsd:complexType name="TestFieldType"> <xsd:attribute name="testattribute" use="optional" type="xsd:string"/> </xsd:complexType> </xsd:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266b-1.xsd���������������������������������0000664�0000000�0000000�00000001213�14211403446�0024652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xsd:schema xmlns:test2="http://namespaceuri/test2" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:import namespace="http://namespaceuri/test2" schemaLocation="issue_266b-2.xsd"/> <xsd:complexType name="element3"> <xsd:choice> <xsd:element ref="test2:testElement3" /> </xsd:choice> </xsd:complexType> <xsd:attribute name="testAttribute3" type="xsd:string"> <xsd:annotation> <xsd:documentation> <div xmlns="http://www.w3.org/1999/xhtml"> <h3>docs</h3> </div> </xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:schema>�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_266/issue_266b-2.xsd���������������������������������0000664�0000000�0000000�00000001047�14211403446�0024660�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xsd:schema xmlns:test2="http://namespaceuri/test2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://namespaceuri/test2"> <xsd:element name="testElement3"> <xsd:annotation> <xsd:documentation> <div xmlns="http://www.w3.org/1999/xhtml"> <h3>docs blah blah</h3> </div> </xsd:documentation> </xsd:annotation> <xsd:complexType> <xsd:attribute ref="testAttribute3" /> </xsd:complexType> </xsd:element> </xsd:schema>�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_273/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022106�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_273/issue_273.xml������������������������������������0000664�0000000�0000000�00000000453�14211403446�0024355�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<someName x="QA01_sequence" y="2500"> <QA01> <qa01_elem01>13</qa01_elem01> <qa01_elem02>5139</qa01_elem02> <qa01_elem03>170</qa01_elem03> <qa01_elem04 these="attributes" get="dropped">0</qa01_elem04> <qa01_elem05>56</qa01_elem05> <qa01_elem06>11141178</qa01_elem06> </QA01> </someName>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_273/issue_273.xsd������������������������������������0000664�0000000�0000000�00000001005�14211403446�0024345�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="someName"> <xs:complexType> <xs:sequence> <xs:any processContents="lax" minOccurs="1" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="x" use="optional" type="xs:ID" /> <xs:attribute name="y" use="required" type="xs:integer" /> <xs:attribute name="z" use="optional" type="xs:NCName" /> </xs:complexType> </xs:element> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_276/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022111�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_276/dummy.xml����������������������������������������0000664�0000000�0000000�00000000172�14211403446�0023766�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<dummy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd" a2="foo"/> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/issues/issue_276/schema.xsd���������������������������������������0000664�0000000�0000000�00000000757�14211403446�0024102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="dummy"> <xs:complexType> <xs:attributeGroup ref="ag1"/> <xs:attributeGroup ref="ag2"/> </xs:complexType> </xs:element> <xs:attributeGroup name="ag1"> <xs:attribute name="a1" type="xs:string"/> <xs:attributeGroup ref="ag2"/> </xs:attributeGroup> <xs:attributeGroup name="ag2"> <xs:attribute name="a2" type="xs:string"/> </xs:attributeGroup> </xs:schema>�����������������xmlschema-1.10.0/tests/test_cases/mypy/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020046�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/mypy/schema_source.py���������������������������������������������0000775�0000000�0000000�00000003561�14211403446�0023250�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python def main() -> None: import io from pathlib import Path from typing import cast, IO from xml.etree import ElementTree import xmlschema case_dir = Path(__file__).parent.parent col_xsd = case_dir.joinpath('examples/collection/collection.xsd') schema = xmlschema.XMLSchema10(str(col_xsd)) print(f"{schema} from filepath") with open(str(col_xsd)) as fp: schema = xmlschema.XMLSchema10(fp) print(f"{schema} from open(filepath)") with open(str(col_xsd), mode='rb') as bfp: schema = xmlschema.XMLSchema10(bfp) print(f"{schema} from open(filepath, mode='rb'), mode binary") with col_xsd.open() as fp: schema = xmlschema.XMLSchema10(cast(IO[str], fp)) print(f"{schema} from IO[str]") with col_xsd.open(mode='rb') as bfp: schema = xmlschema.XMLSchema10(cast(IO[str], bfp)) print(f"{schema} from IO[bytes]") with col_xsd.open() as fp: schema = xmlschema.XMLSchema10(io.StringIO(fp.read())) print(f"{schema} from io.StringIO()") with col_xsd.open(mode='rb') as bfp: schema = xmlschema.XMLSchema10(io.BytesIO(bfp.read())) print(f"{schema} from io.BytesIO()") xt = ElementTree.parse(col_xsd) namespaces = { 'xs': "http://www.w3.org/2001/XMLSchema", '': "http://example.com/ns/collection", } schema = xmlschema.XMLSchema10(xt, build=False) schema.namespaces.update(namespaces) # FIXME? Provide an init argument? schema.build() print(f"{schema} from ElementTree.ElementTree") schema = xmlschema.XMLSchema10(xt.getroot(), build=False) schema.namespaces.update(namespaces) schema.build() print(f"{schema} from ElementTree.Element") schema = xmlschema.XMLSchema10(xmlschema.XMLResource(str(col_xsd))) print(f"{schema} from xmlschema.XMLResource()") if __name__ == '__main__': main() �����������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/mypy/simple_types.py����������������������������������������������0000775�0000000�0000000�00000001206�14211403446�0023137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python def main() -> None: from pathlib import Path import xmlschema from xmlschema.names import XSD_ENUMERATION from xmlschema.validators import XsdAtomicRestriction case_dir = Path(__file__).parent.parent st_xsd = case_dir.joinpath('features/decoder/simple-types.xsd') schema = xmlschema.XMLSchema10(str(st_xsd)) xsd_type = schema.types['enum1'] if isinstance(xsd_type, XsdAtomicRestriction): assert xsd_type.enumeration == ['one', 'two', 'three'] facet = xsd_type.get_facet(XSD_ENUMERATION) print(facet) xsd_type.is_datetime() if __name__ == '__main__': main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/��������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0021062�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/dummy file #2.txt���������������������������������������0000664�0000000�0000000�00000000015�14211403446�0024037�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������DUMMY CONTENT�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/dummy file.txt������������������������������������������0000664�0000000�0000000�00000000015�14211403446�0023652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������DUMMY CONTENT�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/external_entity.xml�������������������������������������0000664�0000000�0000000�00000000253�14211403446�0025022�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ENTITY ee SYSTEM "http://www.w3schools.com/xml/note.xml"> ]> <root>ⅇ</root> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/malformed.xml�������������������������������������������0000664�0000000�0000000�00000000024�14211403446�0023546�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<malformed_xml_file>������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/unparsed_entity.xml�������������������������������������0000664�0000000�0000000�00000000464�14211403446�0025025�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ELEMENT root (image)> <!ELEMENT image EMPTY> <!ATTLIST image source ENTITY #REQUIRED> <!NOTATION GIF SYSTEM "Logo in GIF format" > <!ENTITY logo_file SYSTEM "logo.gif" NDATA GIF> ]> <root> <image source="logo_file"/> </root> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/unused_external_entity.xml������������������������������0000664�0000000�0000000�00000000252�14211403446�0026404�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ENTITY ee SYSTEM "http://www.w3schools.com/xml/note.xml"> ]> <root>abc</root> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/unused_unparsed_entity.xml������������������������������0000664�0000000�0000000�00000000416�14211403446�0026405�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ELEMENT root (image)*> <!ELEMENT image EMPTY> <!ATTLIST image source ENTITY #REQUIRED> <!NOTATION GIF SYSTEM "Logo in GIF format" > <!ENTITY logo_file SYSTEM "logo.gif" NDATA GIF> ]> <root/> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/resources/with_entity.xml�����������������������������������������0000664�0000000�0000000�00000000201�14211403446�0024144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ELEMENT root (#PCDATA)> <!ENTITY e "abc" > ]> <root>&e;</root> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cases/testfiles���������������������������������������������������������0000664�0000000�0000000�00000013033�14211403446�0020775�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Test-files for xmlschema # # Each uncommented and not empty line creates a test. # # Uncomment the following line and run test_all.py to show an help: # filename --help # # Cases with schema examples examples/collection/collection.xsd --inspect --codegen examples/collection/collection.xsd --inspect --version=1.1 --codegen examples/collection/collection.xml --codegen examples/collection/collection2.xsd --inspect # key constraint examples/collection/collection2.xml --errors 1 examples/collection/collection3.xsd # key and keyref constraints examples/collection/collection3.xml --errors 1 examples/collection/collection3bis.xsd examples/collection/collection3bis.xml --errors 1 examples/collection/collection4.xml --codegen # Many XML comments inserted examples/vehicles/vehicles.xsd --inspect --codegen examples/vehicles/vehicles.xsd --inspect --version=1.1 --codegen examples/vehicles/vehicles.xml --codegen examples/vehicles/vehicles-1_error.xml --errors=1 examples/vehicles/vehicles-2_errors.xml --errors=2 examples/vehicles/vehicles-3_errors.xml --errors=3 # Cases on specific XSD or package features features/attributes/default_attributes.xsd --errors=2 features/attributes/default_attributes.xsd --version=1.1 features/attributes/default_attributes-missing_group.xsd --version=1.1 --errors=1 features/builtins/builtins.xsd features/builtins/builtins.xml features/decoder/simple-types.xsd features/decoder/data2.xml --errors=2 features/decoder/mixed-content.xsd features/decoder/data4-mixed.xml features/derivations/complex-extensions.xsd --errors=1 features/derivations/complex-with-simple-content-restriction.xsd features/derivations/list_types.xsd --errors=1 features/derivations/list_types.xml --errors=2 features/derivations/invalid_enumeration_restriction.xsd --errors=1 features/derivations/invalid_restrictions1.xsd --errors=2 features/elements/type_alternatives.xsd --errors=3 features/elements/type_alternatives.xsd --version=1.1 features/elements/type_alternatives-no-ns.xsd --version=1.1 features/elements/test_alternatives-1.xml --version=1.1 features/models/billion_laughs_model.xsd features/models/circular_model.xsd --errors=1 features/models/illegal-attributes.xsd --errors=1 features/models/illegal-declarations.xsd --errors=3 features/models/illegal-occurs.xsd --errors=2 features/models/invalid_models1.xsd --errors=4 features/models/invalid_models2.xsd --errors=3 features/models/model1.xml --errors=1 features/models/models.xsd features/models/recursive-groups.xsd --errors=2 # Two circular definitions features/models/valid_model1.xsd features/namespaces/default_ns_invalid.xsd --errors=1 features/namespaces/default_ns_valid1.xsd features/namespaces/default_ns_valid2.xsd features/namespaces/import-case1.xsd --errors=1 # Unknown type features/namespaces/import-case2.xsd --errors=1 # Missing namespace import in imported chameleon schema features/namespaces/import-case3.xsd features/namespaces/import-case4a.xsd features/namespaces/import-case4b.xsd features/namespaces/import-case4-1.xml # This and the next are also regression tests for issue #140 features/namespaces/import-case4-2.xml features/namespaces/include-case1.xsd features/namespaces/include-case1bis.xsd features/namespaces/include-case2.xsd features/namespaces/include-case2bis.xsd features/namespaces/include-case3.xsd features/namespaces/include-case4.xsd --errors=2 features/namespaces/include-case5.xsd features/namespaces/include-case6.xsd --errors=1 features/patterns/patterns.xsd features/patterns/patterns.xml --errors=6 # Cases from resolved issues issues/issue_008/issue_008.xsd issues/issue_008/issue_008.xml --errors=1 issues/issue_009/issue_009.xsd --errors=2 issues/issue_013/issue_013.xml issues/issue_013/issue_013-1.xml issues/issue_013/issue_013-2.xml --errors=1 # String too long issues/issue_018/issue_018.xsd --errors=2 # It's an XSD 1.1 schema issues/issue_018/issue_018.xsd --version=1.1 issues/issue_018/issue_018-1.xml --version=1.1 issues/issue_026/issue_026-1.xml issues/issue_026/issue_026-2.xml --errors=1 issues/issue_026/issue_026-3.xml --errors=1 issues/issue_028/issue_028-1.xml issues/issue_028/issue_028-2.xml --errors=1 issues/issue_029/issue_029-1.xml issues/issue_029/issue_029-2.xml --errors=2 issues/issue_029/issue_029-3.xml --errors=1 issues/issue_035/dates.xsd issues/issue_035/dates.xml --errors=1 issues/issue_041/issue_041.xsd issues/issue_041/issue_041.xml issues/issue_045/issue_045.xsd issues/issue_051/issue_051.xml issues/issue_073/issue_073-1.xml issues/issue_073/issue_073-2.xml --errors=1 issues/issue_086/issue_086-1.xml issues/issue_086/issue_086-2.xml issues/issue_105/issue_105.xsd issues/issue_203/issue_203.xsd --errors=1 issues/issue_203/issue_203.xsd --version=1.1 issues/issue_203/issue_203.xml --version=1.1 issues/issue_203/issue_203alt.xsd issues/issue_208/issue_208.xml issues/issue_222/issue_222.xsd issues/issue_222/issue_222.xml -L '' issue_222.xsd issues/issue_223/issue_223.xsd issues/issue_223/issue_223.xml -L '' issue_223.xsd --errors=1 # pattern matching with \n ending issues/issue_243/issue_243.xml --version=1.1 -L '' issue_243.xsd issues/issue_245/issue_245.xml --version=1.1 --errors=2 # duplicated key value with xsi:type issues/issue_245/issue_245-valid.xml --version=1.1 issues/issue_259/issue_259-2.xsd --version=1.1 issues/issue_265/issue_265-1.xsd issues/issue_265/issue_265-2-invalid.xsd --errors=1 issues/issue_265/issue_265-2-override.xsd --version=1.1 issues/issue_266/issue_266-1.xsd issues/issue_266/issue_266-1.xml issues/issue_266/issue_266-2.xsd issues/issue_266/issue_266-2.xml issues/issue_276/schema.xsd issues/issue_276/dummy.xml �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_cli.py������������������������������������������������������������������0000664�0000000�0000000�00000027305�14211403446�0017102�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests of console scripts.""" import unittest from unittest.mock import patch import glob import io import logging import pathlib import os import platform import sys import xmlschema from xmlschema.cli import get_loglevel, get_converter, validate, xml2json, json2xml WORK_DIRECTORY = os.getcwd() class TestConsoleScripts(unittest.TestCase): ctx = None def run_validate(self, *args): with patch.object(sys, 'argv', ['xmlschema-validate'] + list(args)): with self.assertRaises(SystemExit) as self.ctx: validate() def run_xml2json(self, *args): with patch.object(sys, 'argv', ['xmlschema-xml2json'] + list(args)): with self.assertRaises(SystemExit) as self.ctx: xml2json() def run_json2xml(self, *args): with patch.object(sys, 'argv', ['xmlschema-json2xml'] + list(args)): with self.assertRaises(SystemExit) as self.ctx: json2xml() def setUp(self): vehicles_dir = pathlib.Path(__file__).parent.joinpath('test_cases/examples/vehicles/') os.chdir(str(vehicles_dir)) def tearDown(self): os.chdir(WORK_DIRECTORY) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_01(self, mock_out, mock_err): self.run_validate() self.assertEqual(mock_out.getvalue(), '') self.assertIn("the following arguments are required", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_02(self, mock_out, mock_err): self.run_validate('vehicles.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml is valid\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_03(self, mock_out, mock_err): self.run_validate('vehicles-2_errors.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles-2_errors.xml is not valid\n", mock_out.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_04(self, mock_out, mock_err): self.run_validate('unknown.xml') self.assertEqual(mock_err.getvalue(), '') output = mock_out.getvalue() if platform.system() == 'Windows': self.assertIn("The system cannot find the file specified", output) else: self.assertIn("No such file or directory", output) self.assertEqual('1', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_05(self, mock_out, mock_err): self.run_validate(*glob.glob('vehicles*.xml')) self.assertEqual(mock_err.getvalue(), '') output = mock_out.getvalue() self.assertIn("vehicles.xml is valid", output) self.assertIn("vehicles-3_errors.xml is not valid", output) self.assertIn("vehicles-1_error.xml is not valid", output) self.assertIn("vehicles2.xml is valid", output) self.assertIn("vehicles-2_errors.xml is not valid", output) self.assertEqual('6', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_06(self, mock_out, mock_err): self.run_validate('--schema=vehicles.xsd', 'vehicles.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml is valid\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_07(self, mock_out, mock_err): self.run_validate('--version=1.1', 'vehicles.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml is valid\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_validate_command_08(self, mock_out, mock_err): self.run_validate('--lazy', 'vehicles.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml is valid\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_xml2json_command_01(self, mock_out, mock_err): self.run_xml2json() self.assertEqual(mock_out.getvalue(), '') self.assertIn("the following arguments are required", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_xml2json_command_02(self, mock_out, mock_err): self.run_xml2json('vehicles.xml') os.unlink('vehicles.json') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml converted to vehicles.json\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_xml2json_command_03(self, mock_out, mock_err): self.run_xml2json('vehicles.xml', '--schema=vehicles.xsd') os.unlink('vehicles.json') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles.xml converted to vehicles.json\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_xml2json_command_04(self, mock_out, mock_err): self.run_xml2json('vehicles-2_errors.xml') os.unlink('vehicles-2_errors.json') self.assertEqual(mock_err.getvalue(), '') msg = "vehicles-2_errors.xml converted to vehicles-2_errors.json with 2 errors\n" self.assertEqual(msg, mock_out.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_xml2json_command_05(self, mock_out, mock_err): if os.path.isfile('vehicles.json'): os.unlink('vehicles.json') self.run_xml2json('vehicles.xml') self.assertEqual('0', str(self.ctx.exception)) self.run_xml2json('vehicles.xml') with self.assertRaises(ValueError) as ctx: self.run_xml2json('--output=vehicles.json', 'vehicles.xml') self.assertEqual(str(ctx.exception), "'vehicles.json' is not a directory") os.unlink('vehicles.json') self.assertEqual(mock_err.getvalue(), '') self.assertIn("vehicles.xml converted to vehicles.json\n", mock_out.getvalue()) self.assertIn("skip vehicles.json: the destination file exists!", mock_out.getvalue()) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_json2xml_command_01(self, mock_out, mock_err): self.run_json2xml() self.assertEqual(mock_out.getvalue(), '') self.assertIn("the following arguments are required: [JSON_FILE", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_json2xml_command_02(self, mock_out, mock_err): self.run_json2xml('--schema=vehicles.xsd') self.assertEqual(mock_out.getvalue(), '') self.assertIn("the following arguments are required: [JSON_FILE", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_json2xml_command_03(self, mock_out, mock_err): with open('vehicles-test.json', 'w') as fp: xmlschema.to_json('vehicles.xml', fp) self.run_json2xml('vehicles-test.json', '--schema=vehicles.xsd') os.unlink('vehicles-test.json') os.unlink('vehicles-test.xml') self.assertEqual(mock_err.getvalue(), '') self.assertEqual("vehicles-test.json converted to vehicles-test.xml\n", mock_out.getvalue()) self.assertEqual('0', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_json2xml_command_04(self, mock_out, mock_err): with open('vehicles-test.json', 'w') as fp: xmlschema.to_json('vehicles.xml', fp) self.run_json2xml('vehicles-test.json', '--schema=vehicles.xsd') self.assertEqual('0', str(self.ctx.exception)) self.run_json2xml('vehicles-test.json', '--schema=vehicles.xsd') with self.assertRaises(ValueError) as ctx: self.run_json2xml('vehicles-test.json', '--schema=vehicles.xsd', '--output=vehicles-test.xml') self.assertEqual(str(ctx.exception), "'vehicles-test.xml' is not a directory") os.unlink('vehicles-test.json') os.unlink('vehicles-test.xml') self.assertEqual(mock_err.getvalue(), '') self.assertIn("vehicles-test.json converted to vehicles-test.xml\n", mock_out.getvalue()) self.assertIn("skip vehicles-test.xml: the destination file exists!", mock_out.getvalue()) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_wrong_xsd_version(self, mock_out, mock_err): self.run_validate('--version=1.9', 'vehicles.xml') self.assertEqual(mock_out.getvalue(), '') self.assertIn("'1.9' is not a valid XSD version", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) @patch('sys.stderr', new_callable=io.StringIO) @patch('sys.stdout', new_callable=io.StringIO) def test_wrong_defuse(self, mock_out, mock_err): self.run_validate('--defuse=sometimes', 'vehicles.xml') self.assertEqual(mock_out.getvalue(), '') self.assertIn("'sometimes' is not a valid value", mock_err.getvalue()) self.assertEqual('2', str(self.ctx.exception)) def test_get_loglevel(self): self.assertEqual(get_loglevel(0), logging.ERROR) self.assertEqual(get_loglevel(1), logging.WARNING) self.assertEqual(get_loglevel(2), logging.INFO) self.assertEqual(get_loglevel(3), logging.DEBUG) def test_get_converter(self): self.assertIsNone(get_converter(None)) self.assertIs(get_converter('Unordered'), xmlschema.UnorderedConverter) self.assertIs(get_converter('Parker'), xmlschema.ParkerConverter) with self.assertRaises(ValueError): get_converter('Unknown') if __name__ == '__main__': header_template = "Test xmlschema CLI with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_codegen.py��������������������������������������������������������������0000664�0000000�0000000�00000063026�14211403446�0017737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning XSD based code generators. Requires jinja2 optional dependency.""" import unittest import os import datetime import ast import logging import platform import importlib.util import tempfile from collections import namedtuple from pathlib import Path from textwrap import dedent from xml.etree import ElementTree from elementpath import datatypes from xmlschema import XMLSchema10, XMLSchema11 from xmlschema.names import XSD_ANY_TYPE, XSD_STRING, XSD_FLOAT try: import jinja2 except ImportError: jinja2 = None filter_method = None AbstractGenerator = None PythonGenerator = None DemoGenerator = None else: from xmlschema.extras.codegen import filter_method, AbstractGenerator, PythonGenerator class DemoGenerator(AbstractGenerator): formal_language = 'Demo' searchpaths = ['templates/demo'] builtin_types = { 'string': 'str', 'boolean': 'bool', 'float': 'float', 'double': 'double', 'integer': 'int', 'decimal': 'float', 'unsignedByte': 'unsigned short', 'nonNegativeInteger': 'unsigned int', 'positiveInteger': 'unsigned int', } @classmethod @filter_method def class_filter(cls, obj): return str(obj) @staticmethod @filter_method def static_filter(obj): return str(obj) @filter_method def instance_filter(self, obj): return str(obj) @staticmethod def not_a_static_filter(obj): return def not_an_instance_filter(self): return def casepath(relative_path): return str(Path(__file__).absolute().parent.joinpath('test_cases', relative_path)) XSD_TEST = """\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://xmlschema.test/ns" targetNamespace="http://xmlschema.test/ns"> <xs:element name="root" type="xs:string" /> <xs:complexType name="type3"> <xs:sequence> <xs:element name="elem1" type="tns:type1" /> <xs:element name="elem2" type="tns:type2" /> </xs:sequence> </xs:complexType> <xs:complexType name="type2"> <xs:sequence> <xs:element name="elem1" type="tns:type1" /> <xs:element name="elem4" type="tns:type4" maxOccurs="10" /> </xs:sequence> </xs:complexType> <xs:simpleType name="type4"> <xs:restriction base="xs:string" /> </xs:simpleType> <xs:complexType name="type1" /> <xs:simpleType name="type5"> <xs:restriction base="xs:decimal" /> </xs:simpleType> <xs:simpleType name="type6"> <xs:restriction base="xs:float" /> </xs:simpleType> </xs:schema> """ @unittest.skipIf(jinja2 is None, "jinja2 library is not installed!") class TestAbstractGenerator(unittest.TestCase): schema_class = XMLSchema10 generator_class = DemoGenerator @classmethod def setUpClass(cls): cls.schema = cls.schema_class(XSD_TEST) cls.searchpath = Path(__file__).absolute().parent.joinpath('templates/filters/') cls.generator = cls.generator_class(cls.schema, str(cls.searchpath)) cls.col_dir = casepath('examples/collection') cls.col_xsd_file = casepath('examples/collection/collection.xsd') cls.col_xml_file = casepath('examples/collection/collection.xml') cls.col_schema = cls.schema_class(cls.col_xsd_file) def test_formal_language(self): self.assertEqual(self.generator_class.formal_language, 'Demo') with self.assertRaises(ValueError) as ec: type('DemoGenerator2', (DemoGenerator,), dict(__module__=__file__, formal_language='Demo2')) self.assertIn("formal_language cannot be changed", str(ec.exception)) class DemoGenerator2(AbstractGenerator): formal_language = 'Demo2' self.assertEqual(DemoGenerator2.formal_language, 'Demo2') with self.assertRaises(ValueError) as ec: type('DemoGenerator3', (DemoGenerator, DemoGenerator2), dict(__module__=__file__)) self.assertIn("ambiguous formal_language", str(ec.exception)) DemoGenerator2.formal_language = 'Demo' class DemoGenerator3(DemoGenerator, DemoGenerator2): pass self.assertEqual(DemoGenerator3.formal_language, 'Demo') @unittest.skipIf(platform.system() == 'Windows', 'Avoiding unnecessary tests on Windows file paths ...') def test_searchpaths(self): self.assertIsInstance(DemoGenerator.searchpaths, list) self.assertTrue(str(DemoGenerator.searchpaths[0]).endswith('templates/demo')) with self.assertRaises(ValueError) as ec: type('DemoGenerator2', (AbstractGenerator,), dict(__module__=__file__, searchpaths=['/not-a-dir'])) self.assertIn("path '/not-a-dir' is not a directory!", str(ec.exception)) def test_schema_argument(self): generator = self.generator_class(self.schema) class_name = generator.__class__.__name__ namespace = 'http://xmlschema.test/ns' self.assertIs(generator.schema, self.schema) self.assertIsInstance(generator._env, jinja2.Environment) self.assertEqual(repr(generator), "{}(namespace={!r})".format(class_name, namespace)) generator = self.generator_class(self.col_xsd_file) self.assertIsInstance(generator.schema, XMLSchema11) self.assertEqual(repr(generator), "{}(schema='collection.xsd')".format(class_name)) def test_searchpath_argument(self): class DemoGenerator2(AbstractGenerator): formal_language = 'Demo2' with self.assertRaises(ValueError) as ec: DemoGenerator2(self.schema) self.assertIn("no search paths defined!", str(ec.exception)) generator = DemoGenerator2(self.schema, '/tmp') self.assertIsInstance(generator._env.loader, jinja2.loaders.FileSystemLoader) def test_types_map_argument(self): types_map = {'foo': 'int', 'bar': 'str'} generator = self.generator_class(self.schema, types_map=types_map) self.assertNotIn('foo', generator.types_map) self.assertIn('{http://xmlschema.test/ns}foo', generator.types_map) self.assertIn(XSD_ANY_TYPE, generator.types_map) xsd_source = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="str32"> <xs:restriction base="xs:string"> <xs:maxLength value="32"/> </xs:restriction> </xs:simpleType> </xs:schema> """) types_map = {'str32': 'String32'} generator = self.generator_class(xsd_source, types_map=types_map) self.assertIn('str32', generator.types_map) def test_builtin_types(self): generator = self.generator_class(self.schema) self.assertIn(XSD_ANY_TYPE, generator.builtin_types) self.assertIn(XSD_STRING, generator.builtin_types) self.assertIn(XSD_FLOAT, generator.builtin_types) self.assertIsNot(generator.builtin_types, generator.types_map) self.assertEqual(generator.builtin_types, generator.types_map) def test_list_templates(self): template_dir = Path(__file__).parent.joinpath('templates') language = self.generator_class.formal_language.lower() templates = set(x.name for x in template_dir.glob('{}/*'.format(language))) templates.update(x.name for x in template_dir.glob('filters/*'.format(language))) self.assertSetEqual(set(self.generator.list_templates()), templates) def test_matching_templates(self): self.assertSetEqual(set(self.generator.matching_templates('name*_filter*')), {'name_filter_test.jinja', 'namespace_filter_test.jinja'}) def test_get_template(self): template = self.generator.get_template('type_qname_filter_test.jinja') self.assertIsInstance(template, jinja2.Template) with self.assertRaises(jinja2.TemplateNotFound): self.generator.get_template('foo') def test_select_template(self): template = self.generator.select_template(['foo', 'qname_filter_test.jinja']) self.assertIsInstance(template, jinja2.Template) with self.assertRaises(jinja2.TemplateNotFound): self.generator.select_template(['foo']) def test_render(self): self.assertListEqual(self.generator.render('name_filter_test.jinja'), ['root']) self.assertListEqual( self.generator.render(['name_filter_test.jinja', 'namespace_filter_test.jinja']), ['root', 'http://xmlschema.test/ns'] ) with self.assertRaises(TypeError): self.generator.render(['name_filter_test.jinja', False]) with self.assertRaises(jinja2.TemplateSyntaxError): self.generator.render(['wrong-template.jinja']) logger = logging.getLogger('xmlschema-codegen') with self.assertLogs(logger, level=logging.DEBUG): self.generator.render('unknown') def test_render_to_files(self): with tempfile.TemporaryDirectory() as outdir: files = self.generator.render_to_files('name_filter_test.jinja', output_dir=outdir) self.assertListEqual(files, [os.path.join(outdir, 'name_filter_test')]) files = self.generator.render_to_files( ['name_filter_test.jinja', 'namespace_filter_test.jinja'], output_dir=outdir) self.assertListEqual(files, [os.path.join(outdir, 'namespace_filter_test')]) with tempfile.TemporaryDirectory() as outdir: files = self.generator.render_to_files( ['name_filter_test.jinja', 'namespace_filter_test.jinja'], output_dir=outdir ) self.assertSetEqual(set(files), { os.path.join(outdir, 'name_filter_test'), os.path.join(outdir, 'namespace_filter_test'), }) with tempfile.TemporaryDirectory() as outdir: files = self.generator.render_to_files('name*', output_dir=outdir) self.assertSetEqual(set(files), { os.path.join(outdir, 'name_filter_test'), os.path.join(outdir, 'namespace_filter_test'), }) with tempfile.TemporaryDirectory() as outdir: with self.assertRaises(TypeError): self.generator.render_to_files( ['name_filter_test.jinja', False], output_dir=outdir) with self.assertRaises(jinja2.TemplateSyntaxError): self.generator.render_to_files(['wrong-template.jinja'], output_dir=outdir) logger = logging.getLogger('xmlschema-codegen') with self.assertLogs(logger, level=logging.DEBUG): with self.assertRaises(jinja2.TemplateSyntaxError): self.generator.render_to_files('*', output_dir=outdir) with self.assertLogs(logger, level=logging.DEBUG): self.generator.render_to_files('unknown', output_dir=outdir) def test_language_type_filter(self): self.assertListEqual(self.generator.render('demo_type_filter_test.jinja'), ['str']) type4 = self.schema.types['type4'] self.assertEqual(self.generator.filters['demo_type'](type4), 'str') generator = DemoGenerator(self.schema, types_map={'type4': 'demo_string'}) self.assertEqual(generator.filters['demo_type'](type4), 'demo_string') class DemoGenerator2(DemoGenerator): @filter_method def demo_type(self, _): return 'foo' generator = DemoGenerator2(self.schema) self.assertEqual(generator.filters['demo_type'](type4), 'foo') generator = DemoGenerator2(self.schema, types_map={'type4': 'demo_string'}) self.assertEqual(generator.filters['demo_type'](type4), 'foo') def test_filter_decorators(self): dt = datetime.datetime(1999, 12, 31, 23, 59, 59) if self.generator_class is DemoGenerator: demo_gen = DemoGenerator(self.schema) self.assertEqual(demo_gen.filters['instance_filter'](dt), '1999-12-31 23:59:59') self.assertEqual(demo_gen.filters['static_filter'](dt), '1999-12-31 23:59:59') self.assertEqual(demo_gen.filters['class_filter'](dt), '1999-12-31 23:59:59') else: with self.assertRaises(KeyError): self.generator.filters['instance_filter'](dt) def test_map_type(self): self.assertEqual(self.generator.map_type(None), '') self.assertEqual(self.generator.map_type(self.schema.elements['root']), 'str') self.assertEqual(self.generator.map_type(self.schema.types['type1']), '') self.assertEqual(self.generator.map_type(self.schema.types['type2']), '') self.assertEqual(self.generator.map_type(self.schema.types['type4']), 'str') self.assertEqual(self.generator.map_type(self.schema.types['type5']), 'float') self.assertEqual(self.generator.map_type(self.schema.types['type6']), 'float') date_type = self.schema.meta_schema.types['date'] self.assertEqual(self.generator.map_type(date_type), '') def test_name_filter(self): xsd_element = self.schema.elements['root'] self.assertEqual(self.generator.filters['name'](xsd_element), 'root') self.assertListEqual(self.generator.render('name_filter_test.jinja'), ['root']) self.assertEqual(self.generator.name(None), 'none') self.assertEqual(self.generator.name(''), '') self.assertEqual(self.generator.name('foo'), 'foo') self.assertEqual(self.generator.name('{http://xmlschema.test/ns}foo'), 'foo') self.assertEqual(self.generator.name('ns:foo'), 'foo') self.assertEqual(self.generator.name('0:foo'), '') self.assertEqual(self.generator.name('1'), 'none') FakeElement = namedtuple('XsdElement', 'local_name name') fake_element = FakeElement(1, 2) self.assertEqual(self.generator.name(fake_element), '') def test_qname_filter(self): xsd_element = self.schema.elements['root'] self.assertEqual(self.generator.filters['qname'](xsd_element), 'tns__root') self.assertListEqual(self.generator.render('qname_filter_test.jinja'), ['tns__root']) self.assertEqual(self.generator.qname(None), 'none') self.assertEqual(self.generator.qname(''), '') self.assertEqual(self.generator.qname('{wrong'), 'none') self.assertEqual(self.generator.qname('foo'), 'foo') self.assertEqual(self.generator.qname('{http://xmlschema.test/ns}foo'), 'tns__foo') self.assertEqual(self.generator.qname('{http://unknown.test/ns}foo'), 'foo') self.assertEqual(self.generator.qname('ns:foo'), 'ns__foo') self.assertEqual(self.generator.qname('0:foo'), 'none') self.assertEqual(self.generator.qname('1'), 'none') def test_namespace_filter(self): xsd_element = self.schema.elements['root'] tns = 'http://xmlschema.test/ns' self.assertEqual(self.generator.filters['namespace'](xsd_element), tns) self.assertListEqual(self.generator.render('namespace_filter_test.jinja'), [tns]) self.assertEqual(self.generator.namespace(None), '') self.assertEqual(self.generator.namespace(''), '') self.assertEqual(self.generator.namespace('{wrong'), '') self.assertEqual(self.generator.namespace('foo'), '') self.assertEqual(self.generator.namespace('{bar}foo'), 'bar') self.assertEqual(self.generator.namespace('tns:foo'), 'http://xmlschema.test/ns') self.assertEqual(self.generator.namespace('0:foo'), '') self.assertEqual(self.generator.namespace('1'), '') qname = datatypes.QName('http://xmlschema.test/ns', 'tns:foo') self.assertEqual(self.generator.namespace(qname), 'http://xmlschema.test/ns') def test_type_name_filter(self): xsd_element = self.schema.elements['root'] self.assertEqual(self.generator.filters['type_name'](xsd_element), 'string') self.assertListEqual(self.generator.render('type_name_filter_test.jinja'), ['string']) self.assertEqual(self.generator.type_name(None), 'none') unnamed_type = self.col_schema.types['objType'].content[5].type self.assertEqual(self.generator.type_name(unnamed_type), 'none') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="a_type"/> <xs:complexType name="bType"/> <xs:complexType name="c"/> <xs:complexType name="c-1"/> <xs:complexType name="c.2"/> </xs:schema>""")) self.assertEqual(self.generator.type_name(schema.types['a_type']), 'a') self.assertEqual(self.generator.type_name(schema.types['bType']), 'b') self.assertEqual(self.generator.type_name(schema.types['c']), 'c') self.assertEqual(self.generator.type_name(schema.types['a_type'], suffix='Type'), 'aType') self.assertEqual(self.generator.type_name(schema.types['bType'], suffix='Type'), 'bType') self.assertEqual(self.generator.type_name(schema.types['c'], suffix='Type'), 'cType') self.assertEqual(self.generator.type_name(schema.types['c-1']), 'c_1') self.assertEqual(self.generator.type_name(schema.types['c.2']), 'c_2') def test_type_qname_filter(self): xsd_element = self.schema.elements['root'] self.assertEqual(self.generator.filters['type_qname'](xsd_element), 'xs__string') self.assertListEqual( self.generator.render('type_qname_filter_test.jinja'), ['xs__string']) self.assertEqual(self.generator.type_qname(None), 'none') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://xmlschema.test/ns" targetNamespace="http://xmlschema.test/ns"> <xs:complexType name="a_type"/> <xs:complexType name="bType"/> <xs:complexType name="c"/> <xs:complexType name="c-1"/> <xs:complexType name="c.2"/> </xs:schema>""")) self.assertEqual(self.generator.type_qname(schema.types['a_type']), 'tns__a') self.assertEqual(self.generator.type_qname(schema.types['bType']), 'tns__b') self.assertEqual(self.generator.type_qname(schema.types['c']), 'tns__c') self.assertEqual(self.generator.type_qname(schema.types['a_type'], suffix='Type'), 'tns__aType') self.assertEqual(self.generator.type_qname(schema.types['bType'], suffix='Type'), 'tns__bType') self.assertEqual(self.generator.type_qname(schema.types['c'], suffix='Type'), 'tns__cType') self.assertEqual(self.generator.type_qname(schema.types['c-1']), 'tns__c_1') self.assertEqual(self.generator.type_qname(schema.types['c.2']), 'tns__c_2') def test_sort_types_filter(self): xsd_types = self.schema.types sorted_types = [xsd_types['type4'], xsd_types['type5'], xsd_types['type6'], xsd_types['type1'], xsd_types['type2'], xsd_types['type3']] self.assertListEqual( self.generator.filters['sort_types'](xsd_types), sorted_types ) self.assertListEqual( self.generator.filters['sort_types'](xsd_types.values()), sorted_types ) self.assertListEqual( self.generator.filters['sort_types'](list(xsd_types.values())), sorted_types ) self.assertListEqual( self.generator.render('sort_types_filter_test.jinja'), ['type4type5type6type1type2type3'] ) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="type1"> <xs:sequence> <xs:element name="elem1" type="xs:string" /> <xs:element name="elem2" type="type2" /> </xs:sequence> </xs:complexType> <xs:complexType name="type2"> <xs:sequence> <xs:element name="elem1" type="type1" /> <xs:element name="elem2" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema>""")) with self.assertRaises(ValueError) as ec: self.generator.sort_types(schema.types) self.assertIn("circularity found", str(ec.exception)) self.assertListEqual( self.generator.sort_types(schema.types, accept_circularity=True), list(schema.types.values()) ) def test_unknown_filter(self): logger = logging.getLogger('xmlschema-codegen') with self.assertLogs(logger, level=logging.DEBUG): self.assertListEqual(self.generator.render('unknown_filter_test.jinja'), []) def test_is_derivation(self): self.assertFalse(self.generator.extension(self.schema.types['type1'])) self.assertFalse(self.generator.extension(self.schema.types['type1'], 'tns:type1')) self.assertFalse(self.generator.restriction(self.schema.types['type1'], 'tns:type1')) self.assertFalse(self.generator.derivation(self.schema.types['type1'], 'type1')) self.assertFalse(self.generator.restriction(self.schema.types['type6'], 'xs:decimal')) self.assertFalse(self.generator.restriction(self.schema.types['type6'], None)) self.assertFalse(self.generator.derivation(self.schema.types['type1'], 'tns0:type1')) self.assertTrue(self.generator.derivation(self.schema.types['type1'], 'tns:type1')) self.assertTrue(self.generator.restriction(self.schema.types['type6'], 'xs:float')) def test_multi_sequence(self): self.assertFalse(self.generator.multi_sequence(self.schema.types['type3'])) self.assertTrue(self.generator.multi_sequence(self.schema.types['type2'])) self.assertFalse(self.generator.multi_sequence(self.schema.types['type5'])) @unittest.skipIf(jinja2 is None, "jinja2 library is not installed!") class TestAbstractGenerator11(TestAbstractGenerator): schema_class = XMLSchema11 @unittest.skipIf(jinja2 is None, "jinja2 library is not installed!") class TestPythonGenerator(TestAbstractGenerator): generator_class = PythonGenerator def test_formal_language(self): self.assertEqual(PythonGenerator.formal_language, 'Python') def test_map_type(self): self.assertEqual(self.generator.map_type(None), '') self.assertEqual(self.generator.map_type(self.schema.elements['root']), 'str') self.assertEqual(self.generator.map_type(self.schema.types['type1']), '') self.assertEqual(self.generator.map_type(self.schema.types['type2']), '') self.assertEqual(self.generator.map_type(self.schema.types['type4']), 'str') self.assertEqual(self.generator.map_type(self.schema.types['type5']), 'decimal.Decimal') self.assertEqual(self.generator.map_type(self.schema.types['type6']), 'float') def test_language_type_filter(self): self.assertListEqual( self.generator.render('python_type_filter_test.jinja'), ['str'] ) def test_list_templates(self): template_dir = Path(__file__).parent.joinpath('templates') language = self.generator_class.formal_language.lower() templates = {'sample.py.jinja', 'bindings.py.jinja'} templates.update(x.name for x in template_dir.glob('filters/*'.format(language))) self.assertSetEqual(set(self.generator.list_templates()), templates) def test_sample_module(self): generator = PythonGenerator(self.col_xsd_file) python_module = generator.render('sample.py.jinja')[0] ast_module = ast.parse(python_module) self.assertIsInstance(ast_module, ast.Module) def test_bindings_module(self): generator = PythonGenerator(self.col_xsd_file) python_module = generator.render('bindings.py.jinja')[0] ast_module = ast.parse(python_module) self.assertIsInstance(ast_module, ast.Module) collection_dir = Path(__file__).parent.joinpath('test_cases/examples/collection') cwd = os.getcwd() try: os.chdir(str(collection_dir)) with open('collection.py', 'w') as fp: fp.write(python_module) spec = importlib.util.spec_from_file_location('collection', 'collection.py') module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) except SyntaxError: pass else: col_data = module.CollectionBinding.fromsource('collection.xml') col_root = ElementTree.XML(col_data.tostring()) self.assertEqual(col_root.tag, '{http://example.com/ns/collection}collection') finally: os.chdir(cwd) @unittest.skipIf(jinja2 is None, "jinja2 library is not installed!") class TestPythonGenerator11(TestPythonGenerator): schema_class = XMLSchema11 if __name__ == '__main__': import platform header_template = "Test xmlschema code generators with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_converters.py�����������������������������������������������������������0000664�0000000�0000000�00000055464�14211403446�0020534�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import xml.etree.ElementTree as ElementTree from pathlib import Path try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema import XMLSchema, XMLSchemaValidationError, fetch_namespaces from xmlschema.etree import etree_element from xmlschema.dataobjects import DataElement from xmlschema.testing import etree_elements_assert_equal from xmlschema.converters import XMLSchemaConverter, UnorderedConverter, \ ParkerConverter, BadgerFishConverter, AbderaConverter, JsonMLConverter, \ ColumnarConverter from xmlschema.dataobjects import DataElementConverter class TestConverters(unittest.TestCase): @classmethod def setUpClass(cls): cls.col_xsd_filename = cls.casepath('examples/collection/collection.xsd') cls.col_xml_filename = cls.casepath('examples/collection/collection.xml') cls.col_xml_root = ElementTree.parse(cls.col_xml_filename).getroot() cls.col_nsmap = fetch_namespaces(cls.col_xml_filename) cls.col_namespace = cls.col_nsmap['col'] if lxml_etree is not None: cls.col_lxml_root = lxml_etree.parse(cls.col_xml_filename).getroot() else: cls.col_lxml_root = None @classmethod def casepath(cls, relative_path): return str(Path(__file__).parent.joinpath('test_cases', relative_path)) def test_element_class_argument(self): converter = XMLSchemaConverter() self.assertIs(converter.etree_element_class, etree_element) converter = XMLSchemaConverter(etree_element_class=etree_element) self.assertIs(converter.etree_element_class, etree_element) if lxml_etree is not None: converter = XMLSchemaConverter(etree_element_class=lxml_etree.Element) self.assertIs(converter.etree_element_class, lxml_etree.Element) def test_prefix_arguments(self): converter = XMLSchemaConverter(cdata_prefix='#') self.assertEqual(converter.cdata_prefix, '#') converter = XMLSchemaConverter(attr_prefix='%') self.assertEqual(converter.attr_prefix, '%') converter = XMLSchemaConverter(attr_prefix='_') self.assertEqual(converter.attr_prefix, '_') converter = XMLSchemaConverter(attr_prefix='attribute__') self.assertEqual(converter.attr_prefix, 'attribute__') converter = XMLSchemaConverter(text_key='text__') self.assertEqual(converter.text_key, 'text__') def test_strip_namespace_argument(self): # Test for issue #161 converter = XMLSchemaConverter(strip_namespaces=True) col_xsd_filename = self.casepath('examples/collection/collection.xsd') col_xml_filename = self.casepath('examples/collection/collection.xml') col_schema = XMLSchema(col_xsd_filename, converter=converter) self.assertIn('@xmlns:', str(col_schema.decode(col_xml_filename, strip_namespaces=False))) self.assertNotIn('@xmlns:', str(col_schema.decode(col_xml_filename))) def test_lossy_property(self): self.assertTrue(XMLSchemaConverter().lossy) self.assertFalse(XMLSchemaConverter(cdata_prefix='#').lossy) def test_cdata_mapping(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="node" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> """) self.assertEqual( schema.decode('<root>1<node/>2<node/>3</root>'), {'node': [None, None]} ) self.assertEqual( schema.decode('<root>1<node/>2<node/>3</root>', cdata_prefix='#'), {'#1': '1', 'node': [None, None], '#2': '2', '#3': '3'} ) def test_preserve_root__issue_215(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xmlschema.test/ns" targetNamespace="http://xmlschema.test/ns"> <xs:element name="a"> <xs:complexType> <xs:sequence> <xs:element name="b1" type="xs:string" maxOccurs="unbounded"/> <xs:element name="b2" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> """) xml_data = """<tns:a xmlns:tns="http://xmlschema.test/ns"><b1/><b2/></tns:a>""" obj = schema.decode(xml_data) self.assertListEqual(list(obj), ['@xmlns:tns', 'b1', 'b2']) self.assertEqual(schema.encode(obj).tag, '{http://xmlschema.test/ns}a') obj = schema.decode(xml_data, preserve_root=True) self.assertListEqual(list(obj), ['tns:a']) root = schema.encode(obj, preserve_root=True, path='tns:a', namespaces={'tns': 'http://xmlschema.test/ns'}) self.assertEqual(root.tag, '{http://xmlschema.test/ns}a') root = schema.encode(obj, preserve_root=True, path='{http://xmlschema.test/ns}a') self.assertEqual(root.tag, '{http://xmlschema.test/ns}a') root = schema.encode(obj, preserve_root=True) self.assertEqual(root.tag, '{http://xmlschema.test/ns}a') def test_etree_element_method(self): converter = XMLSchemaConverter() elem = converter.etree_element('A') self.assertIsNone(etree_elements_assert_equal(elem, etree_element('A'))) elem = converter.etree_element('A', attrib={}) self.assertIsNone(etree_elements_assert_equal(elem, etree_element('A'))) def test_columnar_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=ColumnarConverter) obj = col_schema.decode(self.col_xml_filename) self.assertIn("'authorid'", str(obj)) self.assertNotIn("'author_id'", str(obj)) self.assertNotIn("'author__id'", str(obj)) obj = col_schema.decode(self.col_xml_filename, attr_prefix='_') self.assertNotIn("'authorid'", str(obj)) self.assertIn("'author_id'", str(obj)) self.assertNotIn("'author__id'", str(obj)) obj = col_schema.decode(self.col_xml_filename, attr_prefix='__') self.assertNotIn("'authorid'", str(obj)) self.assertNotIn("'author_id'", str(obj)) self.assertIn("'author__id'", str(obj)) col_schema = XMLSchema(self.col_xsd_filename) obj = col_schema.decode(self.col_xml_filename, converter=ColumnarConverter, attr_prefix='__') self.assertNotIn("'authorid'", str(obj)) self.assertNotIn("'author_id'", str(obj)) self.assertIn("'author__id'", str(obj)) def test_data_element_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=DataElementConverter) obj = col_schema.decode(self.col_xml_filename) self.assertIsInstance(obj, DataElement) self.assertEqual(obj.tag, self.col_xml_root.tag) self.assertEqual(obj.nsmap, self.col_nsmap) def test_decode_encode_default_converter(self): col_schema = XMLSchema(self.col_xsd_filename) # Decode from XML file obj1 = col_schema.decode(self.col_xml_filename) self.assertIn("'@xmlns:col'", repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Decode from lxml.etree.Element tree if self.col_lxml_root is not None: obj2 = col_schema.decode(self.col_lxml_root) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree providing namespaces obj2 = col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree without namespaces obj2 = col_schema.decode(self.col_xml_root) self.assertNotIn("'@xmlns:col'", repr(obj2)) self.assertNotEqual(obj1, obj2) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_default_converter_with_preserve_root(self): col_schema = XMLSchema(self.col_xsd_filename) # Decode from XML file obj1 = col_schema.decode(self.col_xml_filename, preserve_root=True) self.assertIn("'col:collection'", repr(obj1)) self.assertIn("'@xmlns:col'", repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Decode from lxml.etree.Element tree if self.col_lxml_root is not None: obj2 = col_schema.decode(self.col_lxml_root, preserve_root=True) self.assertIn("'col:collection'", repr(obj2)) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree providing namespaces obj2 = col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap, preserve_root=True) self.assertIn("'col:collection'", repr(obj2)) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree without namespaces obj2 = col_schema.decode(self.col_xml_root, preserve_root=True) self.assertNotIn("'col:collection'", repr(obj2)) self.assertNotIn("'@xmlns:col'", repr(obj2)) self.assertNotEqual(obj1, obj2) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2, preserve_root=True) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_unordered_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=UnorderedConverter) # Decode from XML file obj1 = col_schema.decode(self.col_xml_filename) self.assertIn("'@xmlns:col'", repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Decode from lxml.etree.Element tree if self.col_lxml_root is not None: obj2 = col_schema.decode(self.col_lxml_root) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree providing namespaces obj2 = col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree without namespaces obj2 = col_schema.decode(self.col_xml_root) self.assertNotIn("'@xmlns:col'", repr(obj2)) self.assertNotEqual(obj1, obj2) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_unordered_converter_with_preserve_root(self): col_schema = XMLSchema(self.col_xsd_filename, converter=UnorderedConverter) # Decode from XML file obj1 = col_schema.decode(self.col_xml_filename, preserve_root=True) self.assertIn("'col:collection'", repr(obj1)) self.assertIn("'@xmlns:col'", repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Decode from lxml.etree.Element tree if self.col_lxml_root is not None: obj2 = col_schema.decode(self.col_lxml_root, preserve_root=True) self.assertIn("'col:collection'", repr(obj2)) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree providing namespaces obj2 = col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap, preserve_root=True) self.assertIn("'col:collection'", repr(obj2)) self.assertIn("'@xmlns:col'", repr(obj2)) self.assertEqual(obj1, obj2) # Decode from ElementTree.Element tree without namespaces obj2 = col_schema.decode(self.col_xml_root, preserve_root=True) self.assertNotIn("'col:collection'", repr(obj2)) self.assertNotIn("'@xmlns:col'", repr(obj2)) self.assertNotEqual(obj1, obj2) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap, preserve_root=True) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2, preserve_root=True) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_parker_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=ParkerConverter) obj1 = col_schema.decode(self.col_xml_filename) with self.assertRaises(XMLSchemaValidationError) as ec: col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIn("missing required attribute 'id'", str(ec.exception)) def test_decode_encode_badger_fish_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=BadgerFishConverter) obj1 = col_schema.decode(self.col_xml_filename) self.assertIn("'@xmlns'", repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # With ElementTree namespaces are not mapped obj2 = col_schema.decode(self.col_xml_root) self.assertNotIn("'@xmlns'", repr(obj2)) self.assertNotEqual(obj1, obj2) self.assertEqual(obj1, col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap)) # With lxml.etree namespaces are mapped if self.col_lxml_root is not None: self.assertEqual(obj1, col_schema.decode(self.col_lxml_root)) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_abdera_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=AbderaConverter) obj1 = col_schema.decode(self.col_xml_filename) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Namespace mapping is required with self.assertRaises(XMLSchemaValidationError) as ec: col_schema.encode(obj1, path='./{%s}collection' % self.col_namespace) self.assertIn("'xsi:schemaLocation' attribute not allowed", str(ec.exception)) # With ElementTree namespaces are not mapped obj2 = col_schema.decode(self.col_xml_root) self.assertNotEqual(obj1, obj2) self.assertEqual(obj1, col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap)) # With lxml.etree namespaces are mapped if self.col_lxml_root is not None: self.assertEqual(obj1, col_schema.decode(self.col_lxml_root)) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_jsonml_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=JsonMLConverter) obj1 = col_schema.decode(self.col_xml_filename) self.assertIn('col:collection', repr(obj1)) self.assertIn('xmlns:col', repr(obj1)) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1, path='./{%s}collection' % self.col_namespace) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # With ElementTree namespaces are not mapped obj2 = col_schema.decode(self.col_xml_root) self.assertNotIn('col:collection', repr(obj2)) self.assertNotEqual(obj1, obj2) self.assertEqual(obj1, col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap)) # With lxml.etree namespaces are mapped if self.col_lxml_root is not None: self.assertEqual(obj1, col_schema.decode(self.col_lxml_root)) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_columnar_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=ColumnarConverter) obj1 = col_schema.decode(self.col_xml_filename) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # Namespace mapping is required with self.assertRaises(XMLSchemaValidationError) as ec: col_schema.encode(obj1, path='./{%s}collection' % self.col_namespace) self.assertIn("'xsi:schemaLocation' attribute not allowed", str(ec.exception)) # With ElementTree namespaces are not mapped obj2 = col_schema.decode(self.col_xml_root) self.assertNotEqual(obj1, obj2) self.assertEqual(obj1, col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap)) # With lxml.etree namespaces are mapped if self.col_lxml_root is not None: self.assertEqual(obj1, col_schema.decode(self.col_lxml_root)) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) def test_decode_encode_data_element_converter(self): col_schema = XMLSchema(self.col_xsd_filename, converter=DataElementConverter) obj1 = col_schema.decode(self.col_xml_filename) # self.assertIn('col:collection', repr(obj1)) self.assertIn('col', obj1.nsmap) root = col_schema.encode(obj1, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1, path='./{%s}collection' % self.col_namespace) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj1) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) # With ElementTree namespaces are not mapped obj2 = col_schema.decode(self.col_xml_root) # Equivalent if compared as Element trees (tag, text, attrib, tail) self.assertIsNone(etree_elements_assert_equal(obj1, obj2)) self.assertIsNone(etree_elements_assert_equal( obj1, col_schema.decode(self.col_xml_root, namespaces=self.col_nsmap) )) # With lxml.etree namespaces are mapped if self.col_lxml_root is not None: self.assertIsNone(etree_elements_assert_equal( obj1, col_schema.decode(self.col_lxml_root) )) root = col_schema.encode(obj2, path='./col:collection', namespaces=self.col_nsmap) self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) root = col_schema.encode(obj2) # No namespace unmap is required self.assertIsNone(etree_elements_assert_equal(self.col_xml_root, root, strict=False)) if __name__ == '__main__': import platform header_template = "Test xmlschema converters with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_dataobjects.py����������������������������������������������������������0000664�0000000�0000000�00000045135�14211403446�0020617�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import xml.etree.ElementTree as ElementTree from pathlib import Path from xmlschema import XMLSchema10, XMLSchema11, fetch_namespaces, etree_tostring, \ XMLSchemaValidationError, DataElement, DataElementConverter, XMLResource from xmlschema.helpers import is_etree_element from xmlschema.dataobjects import DataBindingMeta, DataBindingConverter from xmlschema.testing import etree_elements_assert_equal class TestDataElementInterface(unittest.TestCase): def test_repr(self): self.assertEqual(repr(DataElement('foo')), "DataElement(tag='foo')") def test_value(self): self.assertIsNone(DataElement('foo').value) self.assertEqual(DataElement('foo', value=10).value, 10) self.assertEqual(DataElement('foo', 1.8).value, 1.8) self.assertFalse(DataElement('foo', False).value) def test_attributes(self): self.assertEqual(DataElement('foo').attrib, {}) attrib = {'a': 10, 'b': 'bar'} self.assertEqual(DataElement('foo', attrib=attrib).attrib, attrib) self.assertEqual(DataElement('foo', attrib=attrib).get('a'), 10) self.assertIsNone(DataElement('foo', attrib=attrib).get('c')) data_element = DataElement('foo') data_element.set('b', 9) self.assertIsNone(data_element.get('a')) self.assertEqual(data_element.get('b'), 9) def test_namespaces(self): self.assertEqual(DataElement('foo').nsmap, {}) nsmap = {'tns': 'http://xmlschema.test/ns'} self.assertEqual(DataElement('foo', nsmap=nsmap).nsmap, nsmap) def test_text_value(self): self.assertIsNone(DataElement('foo').text) self.assertEqual(DataElement('foo', value=True).text, 'true') self.assertEqual(DataElement('foo', value=False).text, 'false') self.assertEqual(DataElement('foo', value=10.0).text, '10.0') class TestDataObjects(unittest.TestCase): schema_class = XMLSchema10 converter = DataElementConverter @classmethod def setUpClass(cls): cls.col_xsd_filename = cls.casepath('examples/collection/collection.xsd') cls.col_xml_filename = cls.casepath('examples/collection/collection.xml') cls.col_xml_root = ElementTree.parse(cls.col_xml_filename).getroot() cls.col_nsmap = fetch_namespaces(cls.col_xml_filename) cls.col_namespace = cls.col_nsmap['col'] cls.col_schema = cls.schema_class(cls.col_xsd_filename, converter=cls.converter) @classmethod def casepath(cls, relative_path): return str(Path(__file__).parent.joinpath('test_cases', relative_path)) def test_namespace(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertIsInstance(col_data, DataElement) self.assertEqual(col_data.tag, '{http://example.com/ns/collection}collection') self.assertEqual(col_data.namespace, 'http://example.com/ns/collection') self.assertEqual(col_data[0].tag, 'object') self.assertEqual(col_data[0].namespace, 'http://example.com/ns/collection') self.assertEqual(DataElement('foo').namespace, '') def test_names(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertEqual(col_data.tag, '{http://example.com/ns/collection}collection') self.assertEqual(col_data.name, col_data.tag) self.assertEqual(col_data.prefixed_name, 'col:collection') self.assertEqual(col_data.local_name, 'collection') self.assertEqual(col_data[1].tag, 'object') self.assertEqual(col_data[1].prefixed_name, 'object') self.assertEqual(col_data[1].local_name, 'object') def test_xsd_version(self): self.assertEqual(DataElement(tag=self.col_xml_root.tag).xsd_version, '1.0') xsd_element = self.col_schema.elements['person'] data_element = DataElement(tag=self.col_xml_root.tag, xsd_element=xsd_element) self.assertEqual(data_element.xsd_version, self.col_schema.XSD_VERSION) def test_xsd_element_binding(self): xsd_element = self.col_schema.elements['person'] data_element = DataElement(tag=self.col_xml_root.tag, xsd_element=xsd_element) data_element.xsd_element = xsd_element with self.assertRaises(TypeError) as ec: DataElement(tag=xsd_element.name, xsd_element=self.col_schema) self.assertIn("invalid type for attribute 'xsd_element'", str(ec.exception)) with self.assertRaises(ValueError) as ec: data_element.xsd_element = self.col_schema.elements['collection'] self.assertIn('the instance is already bound to another XSD element', str(ec.exception)) def test_xsd_type_binding(self): xsd_type = self.col_schema.elements['person'].type data_element = DataElement(tag=self.col_xml_root.tag, xsd_type=xsd_type) with self.assertRaises(TypeError) as ec: DataElement(tag=self.col_xml_root.tag, xsd_type=self.col_schema) self.assertIn("invalid type for attribute 'xsd_type'", str(ec.exception)) with self.assertRaises(ValueError) as ec: data_element.xsd_element = self.col_schema.elements['collection'] self.assertIn('the instance is already bound to another XSD type', str(ec.exception)) with self.assertRaises(ValueError) as ec: data_element.xsd_type = self.col_schema.elements['collection'].type self.assertIn('the instance is already bound to another XSD type', str(ec.exception)) def test_mutable_mapping_api(self): data_element = DataElement('root') self.assertEqual(len(data_element), 0) with self.assertRaises(AssertionError): data_element.append(1) data_element.append(DataElement('elem1')) self.assertEqual(len(data_element), 1) self.assertEqual(data_element[0].tag, 'elem1') data_element.insert(0, DataElement('elem0')) self.assertEqual(len(data_element), 2) self.assertEqual(data_element[0].tag, 'elem0') self.assertEqual(data_element[1].tag, 'elem1') data_element[0] = DataElement('elem2') self.assertEqual(data_element[0].tag, 'elem2') del data_element[0] self.assertEqual(len(data_element), 1) self.assertEqual(data_element[0].tag, 'elem1') def test_xpath_api(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertIs(col_data.find('.'), col_data) self.assertIs(col_data.find('*'), col_data[0]) self.assertIs(col_data.find('object[2]'), col_data[1]) self.assertListEqual(col_data.findall('*'), col_data[:]) self.assertListEqual(list(col_data.iterfind('*')), col_data[:]) def test_iter(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertEqual(len(list(col_data.iter())), len(list(self.col_xml_root.iter()))) for elem, data_element in zip(self.col_xml_root.iter(), col_data.iter()): self.assertEqual(elem.tag, data_element.tag) self.assertIsInstance(data_element, DataElement) self.assertEqual(len(list(col_data.iter('*'))), len(list(col_data.iter()))) self.assertEqual(len(list(col_data.iter('object'))), 2) def test_iterchildren(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertListEqual(list(col_data.iterchildren()), col_data[:]) self.assertListEqual(list(col_data.iterchildren('*')), col_data[:]) self.assertListEqual(list(col_data.iterchildren('object')), col_data[:]) self.assertListEqual(list(col_data.iterchildren('position')), []) def test_schema_bindings(self): data_element = DataElement('foo') self.assertIsNone(data_element.xsd_type) col_data = self.col_schema.decode(self.col_xml_filename) self.assertIs(col_data.xsd_type, self.col_schema.elements['collection'].type) with self.assertRaises(ValueError) as ec: col_data.xsd_type = col_data[0].xsd_type self.assertEqual(str(ec.exception), "the instance is already bound to another XSD type") def test_encode_to_element_tree(self): col_data = self.col_schema.decode(self.col_xml_filename) obj = col_data.encode() self.assertTrue(is_etree_element(obj)) self.assertIsInstance(etree_tostring(obj), str) self.assertIsNone(etree_elements_assert_equal(obj, self.col_xml_root, strict=False)) self.assertIsNone( etree_elements_assert_equal(obj, col_data.encode(converter=self.converter)) ) with self.assertRaises(ValueError) as ec: col_data.xsd_type = col_data[0].xsd_type self.assertEqual(str(ec.exception), "the instance is already bound to another XSD type") with self.assertRaises(ValueError) as ec: col_data.xsd_element = col_data[0].xsd_element self.assertEqual(str(ec.exception), "the instance is already bound to another XSD element") any_data = DataElement('a') any_data.append(DataElement('b1', 1999)) any_data.append(DataElement('b2', 'alpha')) any_data.append(DataElement('b3', True)) with self.assertRaises(ValueError) as ec: any_data.encode() self.assertIn("has no schema bindings", str(ec.exception)) root = ElementTree.XML('<a><b1>1999</b1><b2>alpha</b2><b3>true</b3></a>') obj = any_data.encode(validation='skip') self.assertTrue(is_etree_element(obj)) self.assertIsInstance(etree_tostring(obj), str) self.assertIsNone(etree_elements_assert_equal(obj, root, strict=False)) any_data = DataElement('root', attrib={'a1': 49}) any_data.append(DataElement('child', 18.7, attrib={'a2': False})) root = ElementTree.XML('<root a1="49"><child a2="false">18.7</child></root>') obj = any_data.encode(validation='skip') self.assertTrue(is_etree_element(obj)) self.assertIsInstance(etree_tostring(obj), str) self.assertIsNone(etree_elements_assert_equal(obj, root, strict=False)) def test_serialize_to_xml_source(self): col_data = self.col_schema.decode(self.col_xml_filename) xml_source = col_data.tostring() self.assertTrue(xml_source.startswith('<col:collection ')) self.assertTrue(xml_source.endswith('</col:collection>')) def test_validation(self): with self.assertRaises(ValueError) as ec: DataElement(self.col_xml_root).validate() self.assertIn("has no schema bindings", str(ec.exception)) col_data = self.col_schema.decode(self.col_xml_filename) self.assertIsNone(col_data.validate()) self.assertTrue(col_data.is_valid()) self.assertListEqual(list(col_data.iter_errors()), []) col_data = self.col_schema.decode(self.col_xml_root) self.assertEqual(col_data.nsmap, {}) self.assertTrue(col_data.is_valid()) # FIXME: are namespaces really needed for validation of data elements??? # (that use iter_encode() instead of iter_decode() ...) self.assertTrue(col_data.is_valid(namespaces={ 'col': 'http://example.com/ns/collection', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance' })) # Encoding back using the default namespace is simple with # data elements because you still have the original tags. self.assertTrue(col_data.is_valid(namespaces={ '': 'http://example.com/ns/collection', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance' })) def test_invalid_value_type(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertTrue(col_data.is_valid()) col_data[0][0].value = '1' with self.assertRaises(XMLSchemaValidationError) as ec: col_data.validate() self.assertIn("'1' is not an instance of <class 'int'>", str(ec.exception)) self.assertFalse(col_data.is_valid()) errors = list(col_data.iter_errors()) self.assertEqual(len(errors), 1) self.assertIn("'1' is not an instance of <class 'int'>", str(errors[0])) col_data.find('object/position').value = 1 self.assertTrue(col_data.is_valid()) def test_missing_child(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertTrue(col_data.is_valid()) title = col_data[0].pop(1) with self.assertRaises(XMLSchemaValidationError) as ec: col_data.validate() self.assertIn("Unexpected child with tag 'year' at position 2", str(ec.exception)) self.assertFalse(col_data.is_valid()) errors = list(col_data.iter_errors()) self.assertEqual(len(errors), 1) self.assertIn("Unexpected child with tag 'year' at position 2", str(errors[0])) col_data[0].insert(1, title) self.assertTrue(col_data.is_valid()) def test_max_depth_validation(self): col_data = self.col_schema.decode(self.col_xml_filename) self.assertTrue(col_data.is_valid()) for child in col_data: child.clear() self.assertFalse(col_data.is_valid()) self.assertTrue(col_data.is_valid(max_depth=0)) self.assertTrue(col_data.is_valid(max_depth=1)) self.assertFalse(col_data.is_valid(max_depth=2)) col_data.clear() self.assertTrue(col_data.is_valid(max_depth=0)) self.assertFalse(col_data.is_valid(max_depth=1)) self.assertFalse(col_data.is_valid(max_depth=2)) def test_converter_class(self): converter = self.converter() self.assertFalse(converter.lossy) self.assertTrue(converter.losslessly) class MyDataElement(DataElement): pass col_data = self.col_schema.decode(self.col_xml_filename, converter=converter) self.assertIsInstance(col_data, DataElement) self.assertNotIsInstance(col_data, MyDataElement) converter = self.converter(data_element_class=MyDataElement) self.assertIs(converter.data_element_class, MyDataElement) self.assertIs(converter.copy().data_element_class, MyDataElement) self.col_schema.maps.clear_bindings() # needed for DataBindingConverter ... col_data = self.col_schema.decode(self.col_xml_filename, converter=converter) self.assertIsInstance(col_data, MyDataElement) with self.assertRaises(ValueError) as ec: converter.element_encode(col_data, col_data[0].xsd_element) self.assertEqual("Unmatched tag", str(ec.exception)) class TestDataBindings(TestDataObjects): converter = DataBindingConverter def test_data_binding_metaclass(self): xsd_element = self.col_schema.elements['collection'] collection_class = DataBindingMeta(xsd_element.local_name.title(), (DataElement,), {'xsd_element': xsd_element}) self.assertEqual(collection_class.__name__, 'Collection') self.assertEqual(collection_class.__qualname__, 'Collection') self.assertIsNone(collection_class.__module__) self.assertEqual(collection_class.namespace, 'http://example.com/ns/collection') self.assertEqual(collection_class.xsd_version, self.col_schema.XSD_VERSION) with self.assertRaises(AttributeError) as ec: DataBindingMeta(xsd_element.local_name.title(), (DataElement,), {}) self.assertIn("attribute 'xsd_element' is required", str(ec.exception)) with self.assertRaises(TypeError) as ec: DataBindingMeta(xsd_element.local_name.title(), (DataElement,), {'xsd_element': None}) self.assertIn("None is not an XSD element", str(ec.exception)) def test_element_binding(self): xsd_element = self.col_schema.elements['collection'] xsd_element.binding = None try: binding_class = xsd_element.get_binding() self.assertEqual(binding_class.__name__, 'CollectionBinding') self.assertEqual(binding_class.__qualname__, 'CollectionBinding') self.assertIsNone(binding_class.__module__) self.assertIsNot(xsd_element.binding, DataElement) self.assertTrue(issubclass(xsd_element.binding, DataElement)) self.assertIsInstance(xsd_element.binding, DataBindingMeta) self.assertIs(binding_class, xsd_element.binding) finally: xsd_element.binding = None def test_schema_bindings(self): schema = self.schema_class(self.col_xsd_filename) schema.maps.create_bindings() col_element_class = schema.elements['collection'].binding col_data = col_element_class.fromsource(self.col_xml_filename) self.assertEqual(len(list(col_data.iter())), len(list(self.col_xml_root.iter()))) for elem, data_element in zip(self.col_xml_root.iter(), col_data.iter()): self.assertEqual(elem.tag, data_element.tag) self.assertIsInstance(data_element, DataElement) self.assertIsNone( etree_elements_assert_equal(col_data.encode(), self.col_xml_root, strict=False) ) source = XMLResource(self.col_xml_filename, allow='local') col_data2 = col_element_class.fromsource(source, converter=self.converter) self.assertEqual(len(list(col_data.iter())), len(list(col_data2.iter()))) for data_element, data_element2 in zip(col_data.iter(), col_data2.iter()): self.assertEqual(data_element.tag, data_element2.tag) def test_binding_instance(self): xsd_element = self.col_schema.elements['collection'] xsd_element.binding = None try: binding_class = xsd_element.get_binding() collection_element = binding_class(tag=xsd_element.name) collection_element._encoder = xsd_element with self.assertRaises(ValueError) as ec: binding_class(tag=xsd_element.name, xsd_element=self.col_schema.elements['person']) self.assertIn('already bound to another XSD element', str(ec.exception)) finally: xsd_element.binding = None class TestDataObjects11(TestDataObjects): schema_class = XMLSchema11 class TestDataBindings11(TestDataBindings): schema_class = XMLSchema11 if __name__ == '__main__': import platform header_template = "Test xmlschema data objects with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_documents.py������������������������������������������������������������0000664�0000000�0000000�00000044645�14211403446�0020342�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning XML documents""" import unittest import os import io import pathlib import tempfile from decimal import Decimal try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema import XMLSchema10, XMLSchema11, XmlDocument, \ XMLResourceError, XMLSchemaValidationError, XMLSchemaDecodeError, \ to_json, from_json from xmlschema.etree import ElementTree from xmlschema.names import XSD_NAMESPACE, XSI_NAMESPACE from xmlschema.helpers import is_etree_element, is_etree_document from xmlschema.resources import XMLResource from xmlschema.documents import get_context TEST_CASES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_cases/') def casepath(relative_path): return os.path.join(TEST_CASES_DIR, relative_path) class TestXmlDocuments(unittest.TestCase): @classmethod def setUpClass(cls): cls.vh_dir = casepath('examples/vehicles') cls.vh_xsd_file = casepath('examples/vehicles/vehicles.xsd') cls.vh_xml_file = casepath('examples/vehicles/vehicles.xml') cls.col_dir = casepath('examples/collection') cls.col_xsd_file = casepath('examples/collection/collection.xsd') cls.col_xml_file = casepath('examples/collection/collection.xml') def test_to_json_api(self): json_data = to_json(self.col_xml_file, lazy=True) self.assertIsInstance(json_data, str) self.assertIn('"@xmlns:col"', json_data) self.assertIn(r'"name": "Joan Mir\u00f3"', json_data) with self.assertRaises(TypeError) as ctx: to_json(self.col_xml_file, lazy=True, decimal_type=Decimal) self.assertIn("is not JSON serializable", str(ctx.exception)) col_1_error_xml_file = casepath('examples/collection/collection-1_error.xml') json_data, errors = to_json(col_1_error_xml_file, validation='lax', lazy=True) self.assertEqual(len(errors), 1) self.assertIsInstance(errors[0], XMLSchemaDecodeError) self.assertIn('"position": null', json_data) json_data, errors = to_json(col_1_error_xml_file, validation='lax', lazy=True, json_options={'default': lambda x: None}) self.assertEqual(len(errors), 0) self.assertIn('"object": [null, null]', json_data) def test_from_json_api(self): json_data = to_json(self.col_xml_file, lazy=True) with self.assertRaises(TypeError) as ctx: from_json(json_data, self.col_xsd_file) self.assertIn("invalid type <class 'str'> for argument 'schema'", str(ctx.exception)) col_schema = XMLSchema10(self.col_xsd_file) collection = from_json(json_data, schema=col_schema) self.assertEqual(collection.tag, '{http://example.com/ns/collection}collection') col_schema = XMLSchema10(self.col_xsd_file) collection = from_json(json_data, col_schema, json_options={'parse_float': Decimal}) self.assertEqual(collection.tag, '{http://example.com/ns/collection}collection') def test_get_context_with_schema(self): source, schema = get_context(self.col_xml_file) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) source, schema = get_context(self.col_xml_file, self.col_xsd_file) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) col_schema = XMLSchema10(self.col_xsd_file) source, schema = get_context(self.col_xml_file, col_schema) self.assertIsInstance(source, XMLResource) self.assertIs(schema, col_schema) source, schema = get_context(self.vh_xml_file, cls=XMLSchema10) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) source, schema = get_context(self.col_xml_file, cls=XMLSchema11) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema11) source, schema = get_context(XMLResource(self.vh_xml_file)) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) xml_document = XmlDocument(self.vh_xml_file) source, schema = get_context(xml_document) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) self.assertIs(xml_document.schema, schema) # Issue #145 with open(self.vh_xml_file) as f: source, schema = get_context(f, schema=self.vh_xsd_file) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) with open(self.vh_xml_file) as f: source, schema = get_context(XMLResource(f), schema=self.vh_xsd_file) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) with open(self.vh_xml_file) as f: source, schema = get_context(f, base_url=self.vh_dir) self.assertIsInstance(source, XMLResource) self.assertIsInstance(schema, XMLSchema10) def test_get_context_without_schema(self): xml_data = '<text xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' \ ' xmlns:xs="http://www.w3.org/2001/XMLSchema"\n' \ ' xsi:type="xs:string">foo</text>' source, schema = get_context(xml_data) self.assertIsInstance(source, XMLResource) self.assertIs(schema, XMLSchema10.meta_schema) self.assertEqual(source.root.tag, 'text') self.assertTrue(schema.is_valid(source)) with self.assertRaises(ValueError) as ctx: get_context('<empty/>') self.assertEqual(str(ctx.exception), "no schema can be retrieved for the provided XML data") source, schema = get_context('<empty/>', dummy_schema=True) self.assertEqual(source.root.tag, 'empty') self.assertIsInstance(schema, XMLSchema10) col_xml_resource = XMLResource(self.col_xml_file) col_xml_resource.root.attrib.clear() self.assertEqual(col_xml_resource.get_locations(), []) source, schema = get_context(col_xml_resource, self.col_xsd_file) self.assertIs(source, col_xml_resource) self.assertIsInstance(schema, XMLSchema10) self.assertEqual(schema.target_namespace, 'http://example.com/ns/collection') # Schema target namespace doesn't match source namespace vh_schema = XMLSchema10(self.vh_xsd_file) source, schema = get_context(col_xml_resource, vh_schema) self.assertIs(source, col_xml_resource) self.assertIs(schema, vh_schema) self.assertFalse(schema.is_valid(source)) vh_schema.import_schema('http://example.com/ns/collection', self.col_xsd_file) vh_schema.build() source, schema = get_context(col_xml_resource, vh_schema) self.assertIs(source, col_xml_resource) self.assertIs(schema, vh_schema) self.assertTrue(schema.is_valid(source)) def test_xml_document_init_with_schema(self): xml_document = XmlDocument(self.vh_xml_file) self.assertEqual(os.path.basename(xml_document.url), 'vehicles.xml') self.assertEqual(xml_document.errors, ()) self.assertIsInstance(xml_document.schema, XMLSchema10) xml_document = XmlDocument(self.vh_xml_file, cls=XMLSchema11) self.assertIsInstance(xml_document.schema, XMLSchema11) xml_document = XmlDocument(self.vh_xml_file, self.vh_xsd_file) self.assertIsInstance(xml_document.schema, XMLSchema10) vh_schema = XMLSchema10(self.vh_xsd_file) xml_document = XmlDocument(self.vh_xml_file, vh_schema) self.assertIsInstance(xml_document.schema, XMLSchema10) with self.assertRaises(XMLSchemaValidationError) as ctx: XmlDocument(self.vh_xml_file, self.col_xsd_file) self.assertIn('is not an element of the schema', str(ctx.exception)) xml_document = XmlDocument(self.col_xml_file) self.assertEqual(os.path.basename(xml_document.url), 'collection.xml') self.assertIsInstance(xml_document.schema, XMLSchema10) xml_file = casepath('examples/collection/collection-1_error.xml') with self.assertRaises(XMLSchemaValidationError) as ctx: XmlDocument(xml_file) self.assertIn('invalid literal for int() with base 10', str(ctx.exception)) xml_document = XmlDocument(xml_file, validation='lax') self.assertEqual(os.path.basename(xml_document.url), 'collection-1_error.xml') self.assertIsInstance(xml_document.schema, XMLSchema10) self.assertTrue(len(xml_document.errors), 1) with self.assertRaises(ValueError) as ctx: XmlDocument(xml_file, validation='foo') self.assertEqual(str(ctx.exception), "'foo': not a validation mode") def test_xml_document_init_without_schema(self): with self.assertRaises(ValueError) as ctx: XmlDocument('<empty/>') self.assertIn('no schema can be retrieved for the XML resource', str(ctx.exception)) xml_document = XmlDocument('<empty/>', validation='skip') self.assertIsNone(xml_document.schema) self.assertIsInstance(xml_document._fallback_schema, XMLSchema10) self.assertEqual(xml_document._fallback_schema.target_namespace, '') xml_document = XmlDocument( '<tns:empty xmlns:tns="http://example.com/ns" />', validation='skip' ) self.assertIsNone(xml_document.schema) self.assertIsInstance(xml_document._fallback_schema, XMLSchema10) self.assertEqual(xml_document._fallback_schema.target_namespace, xml_document.namespace) def test_xml_document_parse(self): xml_document = XmlDocument(self.vh_xml_file) self.assertEqual(os.path.basename(xml_document.url), 'vehicles.xml') self.assertFalse(xml_document.is_lazy()) xml_file = casepath('examples/vehicles/vehicles-1_error.xml') with self.assertRaises(XMLSchemaValidationError): xml_document.parse(xml_file) xml_document.parse(self.vh_xml_file, lazy=True) self.assertEqual(os.path.basename(xml_document.url), 'vehicles.xml') self.assertTrue(xml_document.is_lazy()) xml_document = XmlDocument(self.vh_xml_file, validation='lax') xml_document.parse(xml_file) self.assertEqual(len(xml_document.errors), 1) def test_xml_document_decode_with_schema(self): xml_document = XmlDocument(self.vh_xml_file) vh_schema = XMLSchema10(self.vh_xsd_file) self.assertEqual(xml_document.decode(), vh_schema.decode(self.vh_xml_file)) namespaces = {'vh': 'http://example.com/ns'} self.assertEqual(xml_document.decode(namespaces=namespaces), vh_schema.decode(self.vh_xml_file, namespaces=namespaces)) self.assertNotEqual(xml_document.decode(namespaces=namespaces), vh_schema.decode(self.vh_xml_file)) xml_file = casepath('examples/collection/collection-1_error.xml') xml_document = XmlDocument(xml_file, validation='lax') col_schema = XMLSchema10(self.col_xsd_file) self.assertEqual(xml_document.decode(), col_schema.decode(xml_file, validation='lax')[0]) xml_document = XmlDocument(xml_file, validation='skip') self.assertEqual(xml_document.decode(), col_schema.decode(xml_file, validation='skip')) self.assertEqual(xml_document.decode(validation='lax'), col_schema.decode(xml_file, validation='lax')[0]) def test_xml_document_decode_without_schema(self): xml_document = XmlDocument('<x:root xmlns:x="ns" />', validation='skip') self.assertIsNone(xml_document.decode()) xml_document = XmlDocument( '<x:root xmlns:x="ns" a="true"><b1>10</b1><b2/></x:root>', validation='skip' ) self.assertEqual(xml_document.decode(), {'@a': 'true', 'b1': ['10'], 'b2': [None]}) def test_xml_document_decode_with_xsi_type(self): xml_data = '<root xmlns:xsi="{}" xmlns:xs="{}" ' \ 'xsi:type="xs:integer">10</root>'.format(XSI_NAMESPACE, XSD_NAMESPACE) xml_document = XmlDocument(xml_data) self.assertEqual(xml_document.decode(), {'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xmlns:xs': 'http://www.w3.org/2001/XMLSchema', '@xsi:type': 'xs:integer', '$': 10}) def test_xml_document_to_json(self): xml_document = XmlDocument(self.col_xml_file, lazy=True) json_data = xml_document.to_json() self.assertIsInstance(json_data, str) self.assertIn('"@xmlns:col"', json_data) self.assertIn(r'"name": "Joan Mir\u00f3"', json_data) self.assertEqual(xml_document.to_json(validation='lax')[0], json_data) self.assertEqual(xml_document.to_json(namespaces=None), json_data) with self.assertRaises(TypeError) as ctx: xml_document.to_json(decimal_type=Decimal) self.assertIn("is not JSON serializable", str(ctx.exception)) fp = io.StringIO() xml_document.to_json(fp=fp) self.assertEqual(fp.getvalue(), json_data) fp.close() fp = io.StringIO() self.assertEqual(xml_document.to_json(fp=fp, validation='lax'), ()) self.assertEqual(fp.getvalue(), json_data) fp.close() col_1_error_xml_file = casepath('examples/collection/collection-1_error.xml') xml_document = XmlDocument(col_1_error_xml_file, validation='lax') json_data, errors = xml_document.to_json() self.assertEqual(len(errors), 1) self.assertIsInstance(errors[0], XMLSchemaDecodeError) self.assertIn('"position": null', json_data) xml_document = XmlDocument(col_1_error_xml_file, validation='lax', lazy=True) json_data, errors = xml_document.to_json(json_options={'default': lambda x: None}) self.assertEqual(len(errors), 0) self.assertIn('"object": [null, null]', json_data) def test_xml_document_write(self): with tempfile.TemporaryDirectory() as dirname: col_file_path = pathlib.Path(dirname).joinpath('collection.xml') xml_document = XmlDocument(self.col_xml_file) with col_file_path.open(mode='wb') as fp: xml_document.write(fp) schema = XMLSchema10(self.col_xsd_file) xml_document = XmlDocument(str(col_file_path), schema=schema) self.assertEqual(xml_document.root.tag, '{http://example.com/ns/collection}collection') self.assertIs(xml_document.schema, schema) col_file_path.unlink() xml_document.write(str(col_file_path)) xml_document = XmlDocument(str(col_file_path), schema=schema) self.assertIs(xml_document.schema, schema) col_file_path.unlink() xml_document.write(str(col_file_path), encoding='unicode') xml_document = XmlDocument(str(col_file_path), schema=schema) self.assertIs(xml_document.schema, schema) col_file_path.unlink() xml_document.write(str(col_file_path), default_namespace="http://example.com/ns/collection") xml_document = XmlDocument(str(col_file_path), schema=schema) self.assertIs(xml_document.schema, schema) if lxml_etree is not None: col_file_path.unlink() col_etree_document = lxml_etree.parse(self.col_xml_file) xml_document = XmlDocument(col_etree_document, base_url=self.col_dir) xml_document.write(str(col_file_path), default_namespace="http://example.com/ns/collection") xml_document = XmlDocument(str(col_file_path), schema=schema) self.assertIs(xml_document.schema, schema) col_file_path.unlink() xml_document = XmlDocument(self.col_xml_file, lazy=True) with self.assertRaises(XMLResourceError) as ctx: xml_document.write(str(col_file_path)) self.assertEqual(str(ctx.exception), "cannot serialize a lazy XML document") def test_xml_document_etree_interface(self): xml_document = XmlDocument(self.vh_xml_file) self.assertIs(xml_document.getroot(), xml_document._root) self.assertTrue(is_etree_element(xml_document.getroot())) self.assertTrue(is_etree_document(xml_document.get_etree_document())) xml_document = XmlDocument(self.vh_xml_file, lazy=1) with self.assertRaises(XMLResourceError) as ctx: xml_document.get_etree_document() self.assertIn('cannot create an ElementTree from a lazy resource', str(ctx.exception)) vh_tree = ElementTree.parse(self.vh_xml_file) xml_document = XmlDocument(vh_tree, base_url=self.vh_dir) self.assertIs(xml_document.source, vh_tree) self.assertIs(xml_document.get_etree_document(), vh_tree) @unittest.skipIf(lxml_etree is None, "Skip: lxml is not available.") def test_xml_document_with_lxml(self): vh_tree = lxml_etree.parse(self.vh_xml_file) xml_document = XmlDocument(vh_tree, base_url=self.vh_dir) self.assertIs(xml_document.get_etree_document(), vh_tree) xml_document = XmlDocument(vh_tree.getroot(), base_url=self.vh_dir) etree_document = xml_document.get_etree_document() self.assertIsNot(etree_document, vh_tree) self.assertTrue(is_etree_document(etree_document)) self.assertTrue(hasattr(etree_document, 'xpath')) self.assertTrue(hasattr(etree_document, 'xslt')) def test_xml_document_tostring(self): xml_document = XmlDocument(self.vh_xml_file) self.assertTrue(xml_document.tostring().startswith('<vh:vehicles')) with self.assertRaises(XMLResourceError): XmlDocument(self.vh_xml_file, lazy=True).tostring() if __name__ == '__main__': import platform header_template = "Test xmlschema's XML documents with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_etree.py����������������������������������������������������������������0000664�0000000�0000000�00000040364�14211403446�0017437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import platform try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema.etree import ElementTree, PyElementTree, ParseError, \ SafeXMLParser, etree_tostring from xmlschema.helpers import etree_getpath, etree_iter_location_hints, \ etree_iterpath, prune_etree from xmlschema.testing import etree_elements_assert_equal TEST_CASES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_cases/') def casepath(relative_path): return os.path.join(TEST_CASES_DIR, relative_path) class TestElementTree(unittest.TestCase): def test_element_string_serialization(self): self.assertRaises(TypeError, etree_tostring, '<element/>') elem = ElementTree.Element('element') self.assertEqual(etree_tostring(elem), '<element />') self.assertEqual(etree_tostring(elem, xml_declaration=True), '<element />') self.assertEqual(etree_tostring(elem, encoding='us-ascii'), b'<element />') self.assertEqual(etree_tostring(elem, encoding='us-ascii', indent=' '), b' <element />') self.assertEqual(etree_tostring(elem, encoding='us-ascii', xml_declaration=True), b'<?xml version="1.0" encoding="us-ascii"?>\n<element />') self.assertEqual(etree_tostring(elem, encoding='ascii'), b"<?xml version='1.0' encoding='ascii'?>\n<element />") self.assertEqual(etree_tostring(elem, encoding='ascii', xml_declaration=False), b'<element />') self.assertEqual(etree_tostring(elem, encoding='utf-8'), b'<element />') self.assertEqual(etree_tostring(elem, encoding='utf-8', xml_declaration=True), b'<?xml version="1.0" encoding="utf-8"?>\n<element />') self.assertEqual(etree_tostring(elem, encoding='iso-8859-1'), b"<?xml version='1.0' encoding='iso-8859-1'?>\n<element />") self.assertEqual(etree_tostring(elem, encoding='iso-8859-1', xml_declaration=False), b"<element />") self.assertEqual(etree_tostring(elem, method='html'), '<element></element>') self.assertEqual(etree_tostring(elem, method='text'), '') root = ElementTree.XML('<root>\n' ' text1\n' ' <elem>text2</elem>\n' '</root>') self.assertEqual(etree_tostring(root, method='text'), '\n text1\n text2') def test_py_element_string_serialization(self): elem = PyElementTree.Element('element') self.assertEqual(etree_tostring(elem), '<element />') self.assertEqual(etree_tostring(elem, xml_declaration=True), '<element />') self.assertEqual(etree_tostring(elem, encoding='us-ascii'), b'<element />') self.assertEqual(etree_tostring(elem, encoding='us-ascii', xml_declaration=True), b'<?xml version="1.0" encoding="us-ascii"?>\n<element />') self.assertEqual(etree_tostring(elem, encoding='ascii'), b"<?xml version='1.0' encoding='ascii'?>\n<element />") self.assertEqual(etree_tostring(elem, encoding='ascii', xml_declaration=False), b'<element />') self.assertEqual(etree_tostring(elem, encoding='utf-8'), b'<element />') self.assertEqual(etree_tostring(elem, encoding='utf-8', xml_declaration=True), b'<?xml version="1.0" encoding="utf-8"?>\n<element />') self.assertEqual(etree_tostring(elem, encoding='iso-8859-1'), b"<?xml version='1.0' encoding='iso-8859-1'?>\n<element />") self.assertEqual(etree_tostring(elem, encoding='iso-8859-1', xml_declaration=False), b"<element />") self.assertEqual(etree_tostring(elem, method='html'), '<element></element>') self.assertEqual(etree_tostring(elem, method='text'), '') root = PyElementTree.XML('<root>\n' ' text1\n' ' <elem>text2</elem>\n' '</root>') self.assertEqual(etree_tostring(root, method='text'), '\n text1\n text2') @unittest.skipIf(lxml_etree is None, 'lxml is not installed ...') def test_lxml_element_string_serialization(self): elem = lxml_etree.Element('element') self.assertEqual(etree_tostring(elem), '<element/>') self.assertEqual(etree_tostring(elem, xml_declaration=True), '<element/>') self.assertEqual(etree_tostring(elem, encoding='us-ascii'), b'<element/>') self.assertEqual(etree_tostring(elem, encoding='us-ascii', xml_declaration=True), b'<?xml version="1.0" encoding="us-ascii"?>\n<element/>') self.assertEqual(etree_tostring(elem, encoding='ascii'), b'<element/>') self.assertEqual(etree_tostring(elem, encoding='ascii', xml_declaration=True), b'<?xml version="1.0" encoding="ascii"?>\n<element/>') self.assertEqual(etree_tostring(elem, encoding='utf-8'), b'<element/>') self.assertEqual(etree_tostring(elem, encoding='utf-8', xml_declaration=True), b'<?xml version="1.0" encoding="utf-8"?>\n<element/>') self.assertEqual(etree_tostring(elem, encoding='iso-8859-1'), b"<?xml version='1.0' encoding='iso-8859-1'?>\n<element/>") self.assertEqual(etree_tostring(elem, encoding='iso-8859-1', xml_declaration=False), b"<element/>") self.assertEqual(etree_tostring(elem, method='html'), '<element></element>') self.assertEqual(etree_tostring(elem, method='text'), '') root = lxml_etree.XML('<root>\n' ' text1\n' ' <elem>text2</elem>\n' '</root>') self.assertEqual(etree_tostring(root, method='text'), '\n text1\n text2') def test_defuse_xml_entities(self): xml_file = casepath('resources/with_entity.xml') elem = ElementTree.parse(xml_file).getroot() self.assertEqual(elem.text, 'abc') parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) with self.assertRaises(PyElementTree.ParseError) as ctx: ElementTree.parse(xml_file, parser=parser) self.assertEqual("Entities are forbidden (entity_name='e')", str(ctx.exception)) def test_defuse_xml_external_entities(self): xml_file = casepath('resources/external_entity.xml') with self.assertRaises(ParseError) as ctx: ElementTree.parse(xml_file) self.assertIn("undefined entity &ee", str(ctx.exception)) parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) with self.assertRaises(PyElementTree.ParseError) as ctx: ElementTree.parse(xml_file, parser=parser) self.assertEqual("Entities are forbidden (entity_name='ee')", str(ctx.exception)) def test_defuse_xml_unused_external_entities(self): xml_file = casepath('resources/unused_external_entity.xml') elem = ElementTree.parse(xml_file).getroot() self.assertEqual(elem.text, 'abc') parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) with self.assertRaises(PyElementTree.ParseError) as ctx: ElementTree.parse(xml_file, parser=parser) self.assertEqual("Entities are forbidden (entity_name='ee')", str(ctx.exception)) def test_defuse_xml_unparsed_entities(self): xml_file = casepath('resources/unparsed_entity.xml') parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) with self.assertRaises(PyElementTree.ParseError) as ctx: ElementTree.parse(xml_file, parser=parser) self.assertEqual("Unparsed entities are forbidden (entity_name='logo_file')", str(ctx.exception)) def test_defuse_xml_unused_unparsed_entities(self): xml_file = casepath('resources/unused_unparsed_entity.xml') elem = ElementTree.parse(xml_file).getroot() self.assertIsNone(elem.text) parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) with self.assertRaises(PyElementTree.ParseError) as ctx: ElementTree.parse(xml_file, parser=parser) self.assertEqual("Unparsed entities are forbidden (entity_name='logo_file')", str(ctx.exception)) def test_etree_iterpath(self): root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/><b3><c3/></b3></a>') items = list(etree_iterpath(root)) self.assertListEqual(items, [ (root, '.'), (root[0], './b1'), (root[0][0], './b1/c1'), (root[0][1], './b1/c2'), (root[1], './b2'), (root[2], './b3'), (root[2][0], './b3/c3') ]) self.assertListEqual(items, list(etree_iterpath(root, tag='*'))) self.assertListEqual(items, list(etree_iterpath(root, path=''))) self.assertListEqual(items, list(etree_iterpath(root, path=None))) self.assertListEqual(list(etree_iterpath(root, path='/')), [ (root, '/'), (root[0], '/b1'), (root[0][0], '/b1/c1'), (root[0][1], '/b1/c2'), (root[1], '/b2'), (root[2], '/b3'), (root[2][0], '/b3/c3') ]) def test_etree_getpath(self): root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/><b3><c3/></b3></a>') self.assertEqual(etree_getpath(root, root), '.') self.assertEqual(etree_getpath(root[0], root), './b1') self.assertEqual(etree_getpath(root[2][0], root), './b3/c3') self.assertEqual(etree_getpath(root[0], root, parent_path=True), '.') self.assertEqual(etree_getpath(root[2][0], root, parent_path=True), './b3') self.assertIsNone(etree_getpath(root, root[0])) self.assertIsNone(etree_getpath(root[0], root[1])) self.assertIsNone(etree_getpath(root, root, parent_path=True)) def test_etree_elements_assert_equal(self): e1 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') e2 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e1)) self.assertIsNone(etree_elements_assert_equal(e1, e2)) if lxml_etree is not None: e2 = lxml_etree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2)) e2 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/><b4/></a>\n') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2) self.assertIn("has lesser children than <Element 'a'", str(ctx.exception)) e2 = ElementTree.XML('<a><b1>text <c1 a="1"/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2) self.assertIn("texts differ: 'text' != 'text '", str(ctx.exception)) e2 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2>text</b2><b3/></a>\n') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("texts differ: None != 'text'", str(ctx.exception)) e2 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>') self.assertIsNone(etree_elements_assert_equal(e1, e2)) e2 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1><b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2) self.assertIn(r"tails differ: '\n' != None", str(ctx.exception)) e2 = ElementTree.XML('<a><b1>text<c1 a="1 "/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2) self.assertIn("attributes differ: {'a': '1'} != {'a': '1 '}", str(ctx.exception)) e2 = ElementTree.XML('<a><b1>text<c1 a="2 "/></b1>\n<b2/><b3/></a>\n') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("attribute 'a' values differ: '1' != '2'", str(ctx.exception)) e2 = ElementTree.XML('<a><!--comment--><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2)) self.assertIsNone(etree_elements_assert_equal(e1, e2, skip_comments=False)) if lxml_etree is not None: e2 = lxml_etree.XML('<a><!--comment--><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') self.assertIsNone(etree_elements_assert_equal(e1, e2)) e1 = ElementTree.XML('<a><b1>+1</b1></a>') e2 = ElementTree.XML('<a><b1>+ 1 </b1></a>') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) e1 = ElementTree.XML('<a><b1>+1</b1></a>') e2 = ElementTree.XML('<a><b1>+1.1 </b1></a>') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("texts differ: '+1' != '+1.1 '", str(ctx.exception)) e1 = ElementTree.XML('<a><b1>1</b1></a>') e2 = ElementTree.XML('<a><b1>true </b1></a>') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) self.assertIsNone(etree_elements_assert_equal(e2, e1, strict=False)) e2 = ElementTree.XML('<a><b1>false </b1></a>') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("texts differ: '1' != 'false '", str(ctx.exception)) e1 = ElementTree.XML('<a><b1> 0</b1></a>') self.assertIsNone(etree_elements_assert_equal(e1, e2, strict=False)) self.assertIsNone(etree_elements_assert_equal(e2, e1, strict=False)) e2 = ElementTree.XML('<a><b1>true </b1></a>') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("texts differ: ' 0' != 'true '", str(ctx.exception)) e1 = ElementTree.XML('<a><b1>text<c1 a="1"/></b1>\n<b2/><b3/></a>\n') e2 = ElementTree.XML('<a><b1>text<c1 a="1"/>tail</b1>\n<b2/><b3/></a>\n') with self.assertRaises(AssertionError) as ctx: etree_elements_assert_equal(e1, e2, strict=False) self.assertIn("tails differ: None != 'tail'", str(ctx.exception)) def test_iter_location_hints(self): elem = ElementTree.XML( """<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/xmlschema/ns-A import-case4a.xsd"/>""" ) self.assertListEqual( list(etree_iter_location_hints(elem)), [('http://example.com/xmlschema/ns-A', 'import-case4a.xsd')] ) elem = ElementTree.XML( """<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd"/>""" ) self.assertListEqual( list(etree_iter_location_hints(elem)), [('', 'schema.xsd')] ) def test_prune_etree(self): root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/><b3><c3/></b3></a>') prune_etree(root, selector=lambda x: x.tag == 'b1') self.assertListEqual([e.tag for e in root.iter()], ['a', 'b2', 'b3', 'c3']) root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/><b3><c3/></b3></a>') prune_etree(root, selector=lambda x: x.tag.startswith('c')) self.assertListEqual([e.tag for e in root.iter()], ['a', 'b1', 'b2', 'b3']) if __name__ == '__main__': header_template = "ElementTree tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_etree_import.py���������������������������������������������������������0000664�0000000�0000000�00000010615�14211403446�0021025�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import sys import importlib import subprocess import platform def is_element_tree_imported(): return '_elementtree' in sys.modules or 'xml.etree.ElementTree' in sys.modules @unittest.skipUnless(platform.python_implementation() == 'CPython', "requires CPython") class TestElementTreeImport(unittest.TestCase): """ Test ElementTree imports using external script or with single-run import tests. For running a single-run import test use one of these commands: python -m unittest tests/test_etree_import.py -k <pattern> python tests/test_etree_import.py -k <pattern> The pattern must match only one test method to be effective, because the import test can be executed once for each run. Example: python -m unittest tests/test_etree_import.py -k before """ @unittest.skipUnless(platform.system() == 'Linux', "requires Linux") def test_element_tree_import_script(self): test_dir = os.path.dirname(__file__) or '.' cmd = [sys.executable, os.path.join(test_dir, 'check_etree_import.py')] process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stderr = process.stderr.decode('utf-8') self.assertTrue("ModuleNotFoundError" not in stderr, msg="Test script fails because a package is missing:\n\n{}".format(stderr)) self.assertIn("\nTest OK:", process.stdout.decode('utf-8'), msg="Wrong import of ElementTree after xmlschema:\n\n{}".format(stderr)) cmd.append('--before') process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.assertTrue("\nTest OK:" in process.stdout.decode('utf-8'), msg="Wrong import of ElementTree before xmlschema:\n\n{}".format(stderr)) def test_import_etree_after(self): if is_element_tree_imported(): return # skip if ElementTree is already imported xmlschema_etree = importlib.import_module('xmlschema.etree') ElementTree = importlib.import_module('xml.etree.ElementTree') self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!") elem = xmlschema_etree.PyElementTree.Element('element') self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />') self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree) self.assertIs(importlib.import_module('xml.etree').ElementTree, ElementTree) self.assertIs(xmlschema_etree.ElementTree, ElementTree) def test_import_etree_before(self): if is_element_tree_imported(): return # skip if ElementTree is already imported ElementTree = importlib.import_module('xml.etree.ElementTree') xmlschema_etree = importlib.import_module('xmlschema.etree') self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!") elem = xmlschema_etree.PyElementTree.Element('element') self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />') self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree) self.assertIs(importlib.import_module('xml.etree').ElementTree, ElementTree) self.assertIs(xmlschema_etree.ElementTree, ElementTree) def test_inconsistent_etree(self): if is_element_tree_imported(): return # skip if ElementTree is already imported importlib.import_module('xml.etree.ElementTree') sys.modules.pop('xml.etree.ElementTree') with self.assertRaises(RuntimeError) as ctx: importlib.import_module('xmlschema') self.assertIn('Inconsistent status for ElementTree module', str(ctx.exception)) if __name__ == '__main__': header_template = "ElementTree import tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_files.py����������������������������������������������������������������0000664�0000000�0000000�00000006242�14211403446�0017432�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module runs tests on XSD or XML files provided by arguments. """ if __name__ == '__main__': import unittest import os import argparse from xmlschema import XMLSchema10, XMLSchema11 from xmlschema.testing import xsd_version_number, defuse_data, \ make_schema_test_class, make_validation_test_class parser = argparse.ArgumentParser(add_help=True) parser.add_argument('--version', dest='version', metavar='VERSION', type=xsd_version_number, default='1.0', help="XSD schema version to use for testing (default is 1.0).") parser.add_argument('--inspect', action="store_true", default=False, help="Inspect using an observed custom schema class.") parser.add_argument('--defuse', metavar='(always, remote, never)', type=defuse_data, default='remote', help="Define when to use the defused XML data loaders. " "Defuse remote data for default.") parser.add_argument('--lxml', dest='lxml', action='store_true', default=False, help='Check also with lxml.etree.XMLSchema (for XSD 1.0)') parser.add_argument( 'files', metavar='[FILE ...]', nargs='*', help='Input files. Each argument can be a file path or a glob pathname. ' 'A "-" stands for standard input. If no arguments are given then processes ' 'all the files included within the scope of the selected applications.' ) args = parser.parse_args() if args.version == '1.0': schema_class = XMLSchema10 check_with_lxml = args.lxml else: schema_class = XMLSchema11 check_with_lxml = False test_num = 1 test_args = argparse.Namespace( errors=0, warnings=0, inspect=args.inspect, locations=(), defuse=args.defuse, skip=False, debug=False ) test_loader = unittest.TestLoader() test_suite = unittest.TestSuite() for test_file in args.files: if not os.path.isfile(test_file): continue elif test_file.endswith('xsd'): test_class = make_schema_test_class( test_file, test_args, test_num, schema_class, check_with_lxml ) test_num += 1 elif test_file.endswith('xml'): test_class = make_validation_test_class( test_file, test_args, test_num, schema_class, check_with_lxml ) test_num += 1 else: continue print("Add test %r for file %r ..." % (test_class.__name__, test_file)) test_suite.addTest(test_loader.loadTestsFromTestCase(test_class)) if test_num == 1: print("No XSD or XML file to test, exiting ...") else: runner = unittest.TextTestRunner() runner.run(test_suite) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_helpers.py��������������������������������������������������������������0000664�0000000�0000000�00000044002�14211403446�0017766�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests on internal helper functions""" import unittest import sys import decimal from collections import OrderedDict from xmlschema import XMLSchema, XMLSchemaParseError from xmlschema.etree import ElementTree, etree_element from xmlschema.names import XSD_NAMESPACE, XSI_NAMESPACE, XSD_SCHEMA, \ XSD_ELEMENT, XSD_SIMPLE_TYPE, XSD_ANNOTATION, XSI_TYPE from xmlschema.helpers import prune_etree, get_namespace, get_qname, \ local_name, get_prefixed_qname, get_extended_qname, raw_xml_encode, \ count_digits, strictly_equal from xmlschema.testing import iter_nested_items from xmlschema.validators.exceptions import XMLSchemaValidationError from xmlschema.validators.helpers import get_xsd_derivation_attribute, \ decimal_validator, qname_validator, \ base64_binary_validator, hex_binary_validator, \ int_validator, long_validator, unsigned_byte_validator, \ unsigned_short_validator, negative_int_validator, error_type_validator from xmlschema.validators.particles import OccursCalculator class TestHelpers(unittest.TestCase): @classmethod def setUpClass(cls): XMLSchema.meta_schema.build() @classmethod def tearDownClass(cls): XMLSchema.meta_schema.clear() def test_get_xsd_derivation_attribute(self): elem = etree_element(XSD_ELEMENT, attrib={ 'a1': 'extension', 'a2': ' restriction', 'a3': '#all', 'a4': 'other', 'a5': 'restriction extension restriction ', 'a6': 'other restriction' }) values = {'extension', 'restriction'} self.assertEqual(get_xsd_derivation_attribute(elem, 'a1', values), 'extension') self.assertEqual(get_xsd_derivation_attribute(elem, 'a2', values), ' restriction') result = get_xsd_derivation_attribute(elem, 'a3', values) self.assertSetEqual(set(result.strip().split()), set('extension restriction'.split())) self.assertRaises(ValueError, get_xsd_derivation_attribute, elem, 'a4', values) result = get_xsd_derivation_attribute(elem, 'a5', values) self.assertEqual(set(result.strip().split()), set('restriction extension restriction'.split())) self.assertRaises(ValueError, get_xsd_derivation_attribute, elem, 'a6', values) self.assertEqual(get_xsd_derivation_attribute(elem, 'a7', values), '') def test_parse_component(self): component = XMLSchema.meta_schema.types['anyType'] elem = etree_element(XSD_SCHEMA) self.assertIsNone(component._parse_child_component(elem)) elem.append(etree_element(XSD_ELEMENT)) self.assertEqual(component._parse_child_component(elem), elem[0]) elem.append(etree_element(XSD_SIMPLE_TYPE)) self.assertRaises(XMLSchemaParseError, component._parse_child_component, elem) self.assertEqual(component._parse_child_component(elem, strict=False), elem[0]) elem.clear() elem.append(etree_element(XSD_ANNOTATION)) self.assertIsNone(component._parse_child_component(elem)) elem.append(etree_element(XSD_SIMPLE_TYPE)) self.assertEqual(component._parse_child_component(elem), elem[1]) elem.append(etree_element(XSD_ELEMENT)) self.assertRaises(XMLSchemaParseError, component._parse_child_component, elem) self.assertEqual(component._parse_child_component(elem, strict=False), elem[1]) elem.clear() elem.append(etree_element(XSD_ANNOTATION)) elem.append(etree_element(XSD_ANNOTATION)) self.assertIsNone(component._parse_child_component(elem, strict=False)) elem.append(etree_element(XSD_SIMPLE_TYPE)) self.assertEqual(component._parse_child_component(elem), elem[2]) def test_raw_xml_encode_function(self): self.assertIsNone(raw_xml_encode(None)) self.assertEqual(raw_xml_encode(True), 'true') self.assertEqual(raw_xml_encode(False), 'false') self.assertEqual(raw_xml_encode(10), '10') self.assertEqual(raw_xml_encode(0), '0') self.assertEqual(raw_xml_encode(1), '1') self.assertEqual(raw_xml_encode('alpha'), 'alpha') self.assertEqual(raw_xml_encode([10, 20, 30]), '10 20 30') self.assertEqual(raw_xml_encode((10, 20, 30)), '10 20 30') def test_count_digits_function(self): self.assertEqual(count_digits(10), (2, 0)) self.assertEqual(count_digits(-10), (2, 0)) self.assertEqual(count_digits(081.2), (2, 1)) self.assertEqual(count_digits(-081.200), (2, 1)) self.assertEqual(count_digits(0.51), (0, 2)) self.assertEqual(count_digits(-0.510), (0, 2)) self.assertEqual(count_digits(-0.510), (0, 2)) self.assertEqual(count_digits(decimal.Decimal('100.0')), (3, 0)) self.assertEqual(count_digits(decimal.Decimal('100.01')), (3, 2)) self.assertEqual(count_digits('100.01'), (3, 2)) self.assertEqual(count_digits(1E-11), (0, 11)) self.assertEqual(count_digits(b'100.0E+4'), (7, 0)) self.assertEqual(count_digits(decimal.Decimal('100.0E+4')), (7, 0)) self.assertEqual(count_digits(decimal.Decimal('100.00001E+4')), (7, 1)) self.assertEqual(count_digits(decimal.Decimal('0100.00E4')), (7, 0)) self.assertEqual(count_digits(decimal.Decimal('0100.00E12')), (15, 0)) self.assertEqual(count_digits(decimal.Decimal('0100.00E19')), (22, 0)) self.assertEqual(count_digits(decimal.Decimal('100.0E-4')), (0, 2)) self.assertEqual(count_digits(decimal.Decimal('0100.00E-4')), (0, 2)) self.assertEqual(count_digits(decimal.Decimal('0100.00E-8')), (0, 6)) self.assertEqual(count_digits(decimal.Decimal('0100.00E-9')), (0, 7)) self.assertEqual(count_digits(decimal.Decimal('0100.00E-12')), (0, 10)) self.assertEqual(count_digits(decimal.Decimal('100.10E-4')), (0, 5)) self.assertEqual(count_digits(decimal.Decimal('0100.10E-12')), (0, 13)) def test_strictly_equal_function(self): self.assertTrue(strictly_equal(10, 10)) self.assertFalse(strictly_equal(10, 10.0)) def test_iter_nested_items_function(self): if sys.version_info >= (3, 6): self.assertListEqual(list(iter_nested_items({'a': 10, 'b': 20})), [10, 20]) self.assertListEqual(list(iter_nested_items([{'a': 10, 'b': 20}, 30])), [10, 20, 30]) with self.assertRaises(TypeError): list(iter_nested_items({'a': 10, 'b': 20}, dict_class=OrderedDict)) with self.assertRaises(TypeError): list(iter_nested_items([10, 20], list_class=tuple)) def test_occurs_calculator_class(self): counter = OccursCalculator() self.assertEqual(repr(counter), 'OccursCalculator(0, 0)') other = OccursCalculator() # Only for test isolation, usually it's a particle. other.min_occurs = 5 other.max_occurs = 10 counter += other self.assertEqual(repr(counter), 'OccursCalculator(5, 10)') counter *= other self.assertEqual(repr(counter), 'OccursCalculator(25, 100)') counter = OccursCalculator() counter.max_occurs = None self.assertEqual(repr(counter), 'OccursCalculator(0, None)') self.assertEqual(repr(counter * other), 'OccursCalculator(0, None)') self.assertEqual(repr(counter + other), 'OccursCalculator(5, None)') self.assertEqual(repr(counter * other), 'OccursCalculator(25, None)') counter.reset() self.assertEqual(repr(counter), 'OccursCalculator(0, 0)') counter.max_occurs = None other.min_occurs = other.max_occurs = 0 self.assertEqual(repr(counter * other), 'OccursCalculator(0, 0)') counter.reset() other.min_occurs = 0 other.max_occurs = None self.assertEqual(repr(counter * other), 'OccursCalculator(0, 0)') self.assertEqual(repr(counter + other), 'OccursCalculator(0, None)') self.assertEqual(repr(counter + other), 'OccursCalculator(0, None)') counter.max_occurs = 1 self.assertEqual(repr(counter * other), 'OccursCalculator(0, None)') def test_get_namespace(self): self.assertEqual(get_namespace(''), '') self.assertEqual(get_namespace('local'), '') self.assertEqual(get_namespace(XSD_ELEMENT), XSD_NAMESPACE) self.assertEqual(get_namespace('{wrong'), '') self.assertEqual(get_namespace(''), '') self.assertEqual(get_namespace(None), '') self.assertEqual(get_namespace('{}name'), '') self.assertEqual(get_namespace('{ }name'), ' ') self.assertEqual(get_namespace('{ ns }name'), ' ns ') def test_get_qname(self): self.assertEqual(get_qname(XSD_NAMESPACE, 'element'), XSD_ELEMENT) self.assertEqual(get_qname(XSD_NAMESPACE, 'element'), XSD_ELEMENT) self.assertEqual(get_qname(XSI_NAMESPACE, 'type'), XSI_TYPE) self.assertEqual(get_qname(XSI_NAMESPACE, ''), '') self.assertEqual(get_qname(XSI_NAMESPACE, None), None) self.assertEqual(get_qname(XSI_NAMESPACE, 0), 0) self.assertEqual(get_qname(XSI_NAMESPACE, False), False) self.assertRaises(TypeError, get_qname, XSI_NAMESPACE, True) self.assertEqual(get_qname(None, True), True) self.assertEqual(get_qname(None, 'element'), 'element') self.assertEqual(get_qname(None, ''), '') self.assertEqual(get_qname('', 'element'), 'element') def test_local_name(self): self.assertEqual(local_name('element'), 'element') self.assertEqual(local_name(XSD_ELEMENT), 'element') self.assertEqual(local_name('xs:element'), 'element') self.assertEqual(local_name(XSD_SCHEMA), 'schema') self.assertEqual(local_name('schema'), 'schema') self.assertEqual(local_name(''), '') self.assertRaises(TypeError, local_name, None) self.assertRaises(ValueError, local_name, '{ns name') self.assertRaises(TypeError, local_name, 1.0) self.assertRaises(TypeError, local_name, 0) def test_get_prefixed_qname(self): namespaces = {'xsd': XSD_NAMESPACE} self.assertEqual(get_prefixed_qname(XSD_ELEMENT, namespaces), 'xsd:element') namespaces = {'xs': XSD_NAMESPACE, 'xsi': XSI_NAMESPACE} self.assertEqual(get_prefixed_qname(XSD_ELEMENT, namespaces), 'xs:element') self.assertEqual(get_prefixed_qname('xs:element', namespaces), 'xs:element') self.assertEqual(get_prefixed_qname('element', namespaces), 'element') self.assertEqual(get_prefixed_qname('', namespaces), '') self.assertEqual(get_prefixed_qname(None, namespaces), None) self.assertEqual(get_prefixed_qname('{uri}element', namespaces), '{uri}element') self.assertEqual(get_prefixed_qname(XSI_TYPE, {}), XSI_TYPE) self.assertEqual(get_prefixed_qname(None, {}), None) self.assertEqual(get_prefixed_qname('', {}), '') self.assertEqual(get_prefixed_qname('type', {'': XSI_NAMESPACE}), 'type') self.assertEqual(get_prefixed_qname('type', {'': ''}), 'type') self.assertEqual(get_prefixed_qname('{}type', {'': ''}), 'type') self.assertEqual(get_prefixed_qname('{}type', {'': ''}, use_empty=False), '{}type') # Attention! in XML the empty namespace (that means no namespace) can be # associated only with empty prefix, so these cases should never happen. self.assertEqual(get_prefixed_qname('{}type', {'p': ''}), 'p:type') self.assertEqual(get_prefixed_qname('type', {'p': ''}), 'type') self.assertEqual(get_prefixed_qname('{ns}type', {'': 'ns'}, use_empty=True), 'type') self.assertEqual(get_prefixed_qname('{ns}type', {'': 'ns'}, use_empty=False), '{ns}type') self.assertEqual( get_prefixed_qname('{ns}type', {'': 'ns', 'p': 'ns'}, use_empty=True), 'p:type') self.assertEqual( get_prefixed_qname('{ns}type', {'': 'ns', 'p': 'ns'}, use_empty=False), 'p:type') self.assertEqual( get_prefixed_qname('{ns}type', {'': 'ns', 'p': 'ns0'}, use_empty=True), 'type') self.assertEqual( get_prefixed_qname('{ns}type', {'': 'ns', 'p': 'ns0'}, use_empty=False), '{ns}type') def test_get_extended_qname(self): namespaces = {'xsd': XSD_NAMESPACE} self.assertEqual(get_extended_qname('xsd:element', namespaces), XSD_ELEMENT) self.assertEqual(get_extended_qname(XSD_ELEMENT, namespaces), XSD_ELEMENT) self.assertEqual(get_extended_qname('xsd:element', namespaces={}), 'xsd:element') self.assertEqual(get_extended_qname('', namespaces), '') namespaces = {'xs': XSD_NAMESPACE} self.assertEqual(get_extended_qname('xsd:element', namespaces), 'xsd:element') namespaces = {'': XSD_NAMESPACE} self.assertEqual(get_extended_qname('element', namespaces), XSD_ELEMENT) def test_prune_etree_function(self): root = ElementTree.XML('<A id="0"><B/><C/><D/></A>') self.assertFalse(prune_etree(root, lambda x: x.tag == 'C')) self.assertListEqual([e.tag for e in root.iter()], ['A', 'B', 'D']) self.assertEqual(root.attrib, {'id': '0'}) root = ElementTree.XML('<A id="1"><B/><C/><D/></A>') self.assertTrue(prune_etree(root, lambda x: x.tag != 'C')) self.assertListEqual([e.tag for e in root.iter()], ['A']) self.assertEqual(root.attrib, {'id': '1'}) class SelectorClass: tag = 'C' @classmethod def class_method(cls, elem): return elem.tag == cls.tag def method(self, elem): return elem.tag != self.tag selector = SelectorClass() root = ElementTree.XML('<A id="0"><B/><C/><D/></A>') self.assertFalse(prune_etree(root, selector.class_method)) self.assertListEqual([e.tag for e in root.iter()], ['A', 'B', 'D']) self.assertEqual(root.attrib, {'id': '0'}) root = ElementTree.XML('<A id="1"><B/><C/><D/></A>') self.assertTrue(prune_etree(root, selector.method)) self.assertListEqual([e.tag for e in root.iter()], ['A']) self.assertEqual(root.attrib, {'id': '1'}) def test_decimal_validator(self): self.assertIsNone(decimal_validator(10)) self.assertIsNone(decimal_validator(10.1)) self.assertIsNone(decimal_validator(10E9)) self.assertIsNone(decimal_validator('34.21')) with self.assertRaises(XMLSchemaValidationError): decimal_validator(float('inf')) with self.assertRaises(XMLSchemaValidationError): decimal_validator(float('nan')) with self.assertRaises(XMLSchemaValidationError): decimal_validator('NaN') with self.assertRaises(XMLSchemaValidationError): decimal_validator('10E9') with self.assertRaises(XMLSchemaValidationError): decimal_validator('ten') def test_qname_validator(self): self.assertIsNone(qname_validator("foo")) self.assertIsNone(qname_validator("bar:foo")) with self.assertRaises(XMLSchemaValidationError): qname_validator("foo:bar:foo") with self.assertRaises(XMLSchemaValidationError): qname_validator("foo: bar") with self.assertRaises(XMLSchemaValidationError): qname_validator(" foo:bar") # strip already done by white-space facet def test_hex_binary_validator(self): self.assertIsNone(hex_binary_validator("aff1c9")) self.assertIsNone(hex_binary_validator("2aF3Bc")) self.assertIsNone(hex_binary_validator("")) with self.assertRaises(XMLSchemaValidationError): hex_binary_validator("aff1c") with self.assertRaises(XMLSchemaValidationError): hex_binary_validator("aF3Bc") with self.assertRaises(XMLSchemaValidationError): hex_binary_validator("xaF3Bc") def test_base64_binary_validator(self): self.assertIsNone(base64_binary_validator("YWVpb3U=")) self.assertIsNone(base64_binary_validator("YWVpb 3U=")) self.assertIsNone(base64_binary_validator('')) with self.assertRaises(XMLSchemaValidationError): base64_binary_validator("YWVpb3U==") def test_int_validator(self): self.assertIsNone(int_validator(2 ** 31 - 1)) self.assertIsNone(int_validator(-2 ** 31)) with self.assertRaises(XMLSchemaValidationError): int_validator(2 ** 31) def test_long_validator(self): self.assertIsNone(long_validator(2 ** 63 - 1)) self.assertIsNone(long_validator(-2 ** 63)) with self.assertRaises(XMLSchemaValidationError): long_validator(2 ** 63) def test_unsigned_byte_validator(self): self.assertIsNone(unsigned_byte_validator(255)) self.assertIsNone(unsigned_byte_validator(0)) with self.assertRaises(XMLSchemaValidationError): unsigned_byte_validator(256) def test_unsigned_short_validator(self): self.assertIsNone(unsigned_short_validator(2 ** 16 - 1)) self.assertIsNone(unsigned_short_validator(0)) with self.assertRaises(XMLSchemaValidationError): unsigned_short_validator(2 ** 16) def test_negative_int_validator(self): self.assertIsNone(negative_int_validator(-1)) self.assertIsNone(negative_int_validator(-2 ** 65)) with self.assertRaises(XMLSchemaValidationError): negative_int_validator(0) def test_error_type_validator(self): with self.assertRaises(XMLSchemaValidationError): error_type_validator('alpha') with self.assertRaises(XMLSchemaValidationError): error_type_validator(0) if __name__ == '__main__': import platform header_template = "Test xmlschema helpers with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_memory.py���������������������������������������������������������������0000664�0000000�0000000�00000013161�14211403446�0017636�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import decimal import pathlib import subprocess import sys import tempfile try: import memory_profiler except ImportError: memory_profiler = None @unittest.skipIf(memory_profiler is None, "Memory profiler is not installed!") class TestMemoryUsage(unittest.TestCase): @staticmethod def check_memory_profile(output): """Check the output of a memory memory profile run on a function.""" mem_usage = [] func_num = 0 for line in output.split('\n'): parts = line.split() if 'def' in parts: func_num += 1 if not parts or not parts[0].isdigit() or len(parts) == 1 \ or not parts[1].replace('.', '').isdigit(): continue mem_usage.append(decimal.Decimal(parts[1])) if func_num > 1: raise ValueError("Cannot the a memory profile output of more than one function!") return max(v - mem_usage[0] for v in mem_usage[1:]) @unittest.skip def test_package_memory_usage(self): test_dir = os.path.dirname(__file__) or '.' cmd = [sys.executable, os.path.join(test_dir, 'check_memory.py'), '1'] output = subprocess.check_output(cmd, universal_newlines=True) package_mem = self.check_memory_profile(output) self.assertLess(package_mem, 20) def test_element_tree_memory_usage(self): test_dir = os.path.dirname(__file__) or '.' xsd10_schema_file = os.path.join( os.path.dirname(os.path.abspath(test_dir)), 'xmlschema/schemas/XSD_1.0/XMLSchema.xsd' ) cmd = [sys.executable, os.path.join(test_dir, 'check_memory.py'), '2', xsd10_schema_file] output = subprocess.check_output(cmd, universal_newlines=True) parse_mem = self.check_memory_profile(output) cmd = [sys.executable, os.path.join(test_dir, 'check_memory.py'), '3', xsd10_schema_file] output = subprocess.check_output(cmd, universal_newlines=True) iterparse_mem = self.check_memory_profile(output) cmd = [sys.executable, os.path.join(test_dir, 'check_memory.py'), '4', xsd10_schema_file] output = subprocess.check_output(cmd, universal_newlines=True) lazy_iterparse_mem = self.check_memory_profile(output) self.assertLess(parse_mem, 2) self.assertLess(lazy_iterparse_mem, parse_mem) self.assertLess(lazy_iterparse_mem, iterparse_mem) def test_decode_memory_usage(self): with tempfile.TemporaryDirectory() as dirname: python_script = pathlib.Path(__file__).parent.joinpath('check_memory.py') xsd_file = pathlib.Path(__file__).parent.absolute().joinpath( 'test_cases/features/decoder/long-sequence-1.xsd' ) xml_file = pathlib.Path(dirname).joinpath('data.xml') with xml_file.open('w') as fp: fp.write('<data ') fp.write('xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ') fp.write(f'xsi:noNamespaceSchemaLocation="{xsd_file.as_uri()}">\n') for k in range(1000): fp.write('<chunk><a><b1/><b2/><b3/></a></chunk>\n') fp.write('</data>\n') cmd = [sys.executable, python_script, '5', str(xml_file)] output = subprocess.check_output(cmd, universal_newlines=True) decode_mem = self.check_memory_profile(output) cmd = [sys.executable, python_script, '6', str(xml_file)] output = subprocess.check_output(cmd, universal_newlines=True) lazy_decode_mem = self.check_memory_profile(output) self.assertLessEqual(decode_mem, 2.6) self.assertLessEqual(lazy_decode_mem, 1.8) def test_validate_memory_usage(self): with tempfile.TemporaryDirectory() as dirname: python_script = pathlib.Path(__file__).parent.joinpath('check_memory.py') xsd_file = pathlib.Path(__file__).parent.absolute().joinpath( 'test_cases/features/decoder/long-sequence-1.xsd' ) xml_file = pathlib.Path(dirname).joinpath('data.xml') with xml_file.open('w') as fp: fp.write('<data ') fp.write('xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ') fp.write(f'xsi:noNamespaceSchemaLocation="{xsd_file.as_uri()}">\n') for k in range(1000): fp.write('<chunk><a><b1/><b2/><b3/></a></chunk>\n') fp.write('</data>\n') cmd = [sys.executable, python_script, '7', str(xml_file)] output = subprocess.check_output(cmd, universal_newlines=True) validate_mem = self.check_memory_profile(output) cmd = [sys.executable, python_script, '8', str(xml_file)] output = subprocess.check_output(cmd, universal_newlines=True) lazy_validate_mem = self.check_memory_profile(output) self.assertLess(validate_mem, 2.6) self.assertLess(lazy_validate_mem, 1.8) if __name__ == '__main__': import platform header_template = "Memory usage tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_namespaces.py�����������������������������������������������������������0000664�0000000�0000000�00000021435�14211403446�0020450�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import sys from xmlschema.names import XSD_NAMESPACE, XSI_NAMESPACE from xmlschema.namespaces import NamespaceResourcesMap, NamespaceMapper, NamespaceView CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') class TestNamespaceResourcesMap(unittest.TestCase): def test_init(self): nsmap = [('tns0', 'schema1.xsd')] self.assertEqual(NamespaceResourcesMap(), {}) self.assertEqual(NamespaceResourcesMap(nsmap), {'tns0': ['schema1.xsd']}) nsmap.append(('tns0', 'schema2.xsd')) self.assertEqual(NamespaceResourcesMap(nsmap), {'tns0': ['schema1.xsd', 'schema2.xsd']}) @unittest.skipIf(sys.version_info[:2] < (3, 6), "Python 3.6+ needed") def test_repr(self): namespaces = NamespaceResourcesMap() namespaces['tns0'] = 'schema1.xsd' namespaces['tns1'] = 'schema2.xsd' self.assertEqual(repr(namespaces), "{'tns0': ['schema1.xsd'], 'tns1': ['schema2.xsd']}") def test_dictionary_methods(self): namespaces = NamespaceResourcesMap() namespaces['tns0'] = 'schema1.xsd' namespaces['tns1'] = 'schema2.xsd' self.assertEqual(namespaces, {'tns0': ['schema1.xsd'], 'tns1': ['schema2.xsd']}) self.assertEqual(len(namespaces), 2) self.assertEqual(set(x for x in namespaces), {'tns0', 'tns1'}) del namespaces['tns0'] self.assertEqual(namespaces, {'tns1': ['schema2.xsd']}) self.assertEqual(len(namespaces), 1) namespaces.clear() self.assertEqual(namespaces, {}) class TestNamespaceMapper(unittest.TestCase): def test_init(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces) self.assertEqual(mapper, namespaces) self.assertIs(namespaces, mapper.namespaces) def test_dictionary_methods(self): namespaces = dict(xs=XSD_NAMESPACE) mapper = NamespaceMapper(namespaces) mapper['xsi'] = XSI_NAMESPACE self.assertEqual(mapper, dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE)) del mapper['xs'] self.assertEqual(len(mapper), 1) self.assertEqual(mapper, dict(xsi=XSI_NAMESPACE)) mapper.clear() self.assertEqual(mapper, {}) def test_strip_namespaces(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces, strip_namespaces=True) self.assertEqual(mapper.map_qname('{%s}name' % XSD_NAMESPACE), 'name') self.assertEqual(mapper.map_qname('{unknown}name'), 'name') mapper.strip_namespaces = False self.assertEqual(mapper.map_qname('{%s}name' % XSD_NAMESPACE), 'xs:name') self.assertEqual(mapper.map_qname('{unknown}name'), '{unknown}name') def test_default_namespace(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces) self.assertIsNone(mapper.default_namespace) mapper[''] = 'tns0' self.assertEqual(mapper.default_namespace, 'tns0') def test_insert_item(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces) mapper.insert_item('xs', XSD_NAMESPACE) self.assertEqual(len(mapper), 2) mapper.insert_item('', XSD_NAMESPACE) self.assertEqual(len(mapper), 3) mapper.insert_item('', XSD_NAMESPACE) self.assertEqual(len(mapper), 3) mapper.insert_item('', 'tns0') self.assertEqual(len(mapper), 4) mapper.insert_item('xs', XSD_NAMESPACE) self.assertEqual(len(mapper), 4) mapper.insert_item('xs', 'tns1') self.assertEqual(len(mapper), 5) mapper.insert_item('xs', 'tns2') self.assertEqual(len(mapper), 6) def test_map_qname(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces) mapper.insert_item('', XSD_NAMESPACE) self.assertEqual(mapper.map_qname(''), '') self.assertEqual(mapper.map_qname('{%s}element' % XSD_NAMESPACE), 'xs:element') mapper.pop('xs') self.assertEqual(mapper.map_qname('{%s}element' % XSD_NAMESPACE), 'element') with self.assertRaises(ValueError) as ctx: mapper.map_qname('{%selement' % XSD_NAMESPACE) self.assertIn("wrong format", str(ctx.exception)) with self.assertRaises(ValueError) as ctx: mapper.map_qname('{%s}element}' % XSD_NAMESPACE) self.assertIn("wrong format", str(ctx.exception)) with self.assertRaises(TypeError) as ctx: mapper.map_qname(None) self.assertIn("must be a string-like object", str(ctx.exception)) with self.assertRaises(TypeError) as ctx: mapper.map_qname(99) self.assertIn("must be a string-like object", str(ctx.exception)) def test_unmap_qname(self): namespaces = dict(xs=XSD_NAMESPACE, xsi=XSI_NAMESPACE) mapper = NamespaceMapper(namespaces) self.assertEqual(mapper.unmap_qname(''), '') self.assertEqual(mapper.unmap_qname('xs:element'), '{%s}element' % XSD_NAMESPACE) self.assertEqual(mapper.unmap_qname('{foo}bar'), '{foo}bar') self.assertEqual(mapper.unmap_qname('xsd:element'), 'xsd:element') with self.assertRaises(ValueError) as ctx: mapper.unmap_qname('xs::element') self.assertIn("wrong format", str(ctx.exception)) with self.assertRaises(TypeError) as ctx: mapper.unmap_qname(None) self.assertIn("must be a string-like object", str(ctx.exception)) with self.assertRaises(TypeError) as ctx: mapper.unmap_qname(99) self.assertIn("must be a string-like object", str(ctx.exception)) self.assertEqual(mapper.unmap_qname('element'), 'element') mapper[''] = 'foo' self.assertEqual(mapper.unmap_qname('element'), '{foo}element') self.assertEqual(mapper.unmap_qname('element', name_table=['element']), 'element') def test_transfer(self): mapper = NamespaceMapper(namespaces={'xs': XSD_NAMESPACE, 'xsi': XSI_NAMESPACE}) namespaces = {'xs': 'foo'} mapper.transfer(namespaces) self.assertEqual(len(mapper), 2) self.assertEqual(len(namespaces), 1) namespaces = {'xs': XSD_NAMESPACE} mapper.transfer(namespaces) self.assertEqual(len(mapper), 2) self.assertEqual(len(namespaces), 0) namespaces = {'xs': XSI_NAMESPACE, 'tns0': 'http://xmlschema.test/ns'} mapper.transfer(namespaces) self.assertEqual(len(mapper), 3) self.assertIn('tns0', mapper) self.assertEqual(len(namespaces), 1) self.assertIn('xs', namespaces) mapper = NamespaceMapper() namespaces = {'xs': XSD_NAMESPACE} mapper.transfer(namespaces) self.assertEqual(mapper, {'xs': XSD_NAMESPACE}) self.assertEqual(namespaces, {}) class TestNamespaceView(unittest.TestCase): def test_init(self): qnames = {'{tns0}name0': 0, '{tns1}name1': 1, 'name2': 2} ns_view = NamespaceView(qnames, 'tns1') self.assertEqual(ns_view, {'name1': 1}) def test_repr(self): qnames = {'{tns0}name0': 0, '{tns1}name1': 1, 'name2': 2} ns_view = NamespaceView(qnames, 'tns0') self.assertEqual(repr(ns_view), "NamespaceView({'name0': 0})") def test_contains(self): qnames = {'{tns0}name0': 0, '{tns1}name1': 1, 'name2': 2} ns_view = NamespaceView(qnames, 'tns1') self.assertIn('name1', ns_view) self.assertNotIn('{tns1}name1', ns_view) self.assertNotIn('{tns0}name0', ns_view) self.assertNotIn('name0', ns_view) self.assertNotIn('name2', ns_view) self.assertNotIn(1, ns_view) def test_as_dict(self): qnames = {'{tns0}name0': 0, '{tns1}name1': 1, '{tns1}name2': 2, 'name3': 3} ns_view = NamespaceView(qnames, 'tns1') self.assertEqual(ns_view.as_dict(), {'name1': 1, 'name2': 2}) self.assertEqual(ns_view.as_dict(True), {'{tns1}name1': 1, '{tns1}name2': 2}) ns_view = NamespaceView(qnames, '') self.assertEqual(ns_view.as_dict(), {'name3': 3}) self.assertEqual(ns_view.as_dict(True), {'name3': 3}) if __name__ == '__main__': import platform header_template = "Test xmlschema namespaces with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_package.py��������������������������������������������������������������0000664�0000000�0000000�00000011107�14211403446�0017717�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests about the packaging of the code""" import unittest import glob import fileinput import os import re import importlib import pathlib class TestPackaging(unittest.TestCase): @classmethod def setUpClass(cls): cls.test_dir = os.path.dirname(os.path.abspath(__file__)) cls.package_dir = os.path.dirname(cls.test_dir) cls.source_dir = os.path.join(cls.package_dir, 'xmlschema') cls.missing_debug = re.compile( r"(\bimport\s+pdb\b|\bpdb\s*\.\s*set_trace\(\s*\)|\bprint\s*\()|\bbreakpoint\s*\(" ) cls.get_version = re.compile(r"(?:\brelease|__version__)(?:\s*=\s*)(\'[^\']*\'|\"[^\"]*\")") def test_forgotten_debug_statements(self): # Exclude explicit debug statements written in the code exclude = { 'cli.py': ['print('], } message = "\nFound a debug missing statement at line %d or file %r: %r" filename = None file_excluded = [] files = glob.glob(os.path.join(self.source_dir, '*.py')) + \ glob.glob(os.path.join(self.source_dir, 'validators/*.py')) for line in fileinput.input(files): if fileinput.isfirstline(): filename = fileinput.filename() file_excluded = exclude.get(os.path.basename(filename), []) lineno = fileinput.filelineno() if lineno in file_excluded: continue match = self.missing_debug.search(line) if match is None or match.group(0) in file_excluded: continue self.assertIsNone(match, message % (lineno, filename, match.group(0))) def test_version(self): message = "\nFound a different version at line %d or file %r: %r (may be %r)." files = [os.path.join(self.source_dir, '__init__.py')] if self.package_dir is not None: files.extend([ os.path.join(self.package_dir, 'setup.py'), os.path.join(self.package_dir, 'doc/conf.py'), ]) version = filename = None for line in fileinput.input(files): if fileinput.isfirstline(): filename = fileinput.filename() lineno = fileinput.filelineno() match = self.get_version.search(line) if match is not None: if version is None: version = match.group(1).strip('\'\"') else: self.assertTrue( version == match.group(1).strip('\'\"'), message % (lineno, filename, match.group(1).strip('\'\"'), version) ) def test_elementpath_requirement(self): package_dir = pathlib.Path(__file__).parent.parent ep_requirement = None for line in fileinput.input(str(package_dir.joinpath('requirements-dev.txt'))): if 'elementpath' in line: ep_requirement = line.strip() self.assertIsNotNone(ep_requirement, msg="Missing elementpath in requirements-dev.txt") for line in fileinput.input(str(package_dir.joinpath('setup.py'))): if 'elementpath' in line: self.assertIn(ep_requirement, line, msg="Unmatched requirement in setup.py") def test_base_schema_files(self): et = importlib.import_module('xml.etree.ElementTree') schemas_dir = os.path.join(self.source_dir, 'schemas') base_schemas = [ 'XSD_1.0/XMLSchema.xsd', 'XSD_1.1/XMLSchema.xsd', 'XHTML/xhtml1-strict.xsd', 'XLINK/xlink.xsd', 'XML/xml_minimal.xsd', 'HFP/XMLSchema-hasFacetAndProperty_minimal.xsd', 'XSI/XMLSchema-instance_minimal.xsd' ] for rel_path in base_schemas: filename = os.path.join(schemas_dir, rel_path) self.assertTrue(os.path.isfile(filename), msg="schema file %r is missing!" % filename) self.assertIsInstance(et.parse(filename), et.ElementTree) if __name__ == '__main__': import platform header_template = "Packaging tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_resources.py������������������������������������������������������������0000664�0000000�0000000�00000212227�14211403446�0020344�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning XML resources""" import unittest import os import pathlib import platform import warnings from io import StringIO, BytesIO from urllib.error import URLError from urllib.request import urlopen from urllib.parse import urlsplit, uses_relative from pathlib import Path, PurePath, PureWindowsPath, PurePosixPath from unittest.mock import patch, MagicMock try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema import fetch_namespaces, fetch_resource, normalize_url, \ fetch_schema, fetch_schema_locations, XMLResource, XMLResourceError, XMLSchema from xmlschema.etree import ElementTree, etree_element, py_etree_element, is_etree_element from xmlschema.names import XSD_NAMESPACE import xmlschema.resources from xmlschema.resources import is_url, is_local_url, is_remote_url, \ url_path_is_file, normalize_locations, LazySelector from xmlschema.testing import SKIP_REMOTE_TESTS TEST_CASES_DIR = str(pathlib.Path(__file__).absolute().parent.joinpath('test_cases')) DRIVE_REGEX = '/[a-zA-Z]:' if platform.system() == 'Windows' else '' def casepath(relative_path): return str(pathlib.Path(TEST_CASES_DIR).joinpath(relative_path)) def is_windows_path(path): """Checks if the path argument is a Windows platform path.""" return '\\' in path or ':' in path or '|' in path def add_leading_slash(path): return '/' + path if path and path[0] not in ('/', '\\') else path def filter_windows_path(path): if path.startswith('/\\'): return path[1:] elif path and path[0] not in ('/', '\\'): return '/' + path else: return path class TestResources(unittest.TestCase): @classmethod def setUpClass(cls): cls.vh_dir = casepath('examples/vehicles') cls.vh_xsd_file = casepath('examples/vehicles/vehicles.xsd') cls.vh_xml_file = casepath('examples/vehicles/vehicles.xml') cls.col_dir = casepath('examples/collection') cls.col_xsd_file = casepath('examples/collection/collection.xsd') cls.col_xml_file = casepath('examples/collection/collection.xml') def check_url(self, url, expected): url_parts = urlsplit(url) if urlsplit(expected).scheme not in uses_relative: expected = add_leading_slash(expected) expected_parts = urlsplit(expected, scheme='file') self.assertEqual(url_parts.scheme, expected_parts.scheme, "%r: Schemes differ." % url) self.assertEqual(url_parts.netloc, expected_parts.netloc, "%r: Netloc parts differ." % url) self.assertEqual(url_parts.query, expected_parts.query, "%r: Query parts differ." % url) self.assertEqual(url_parts.fragment, expected_parts.fragment, "%r: Fragment parts differ." % url) if is_windows_path(url_parts.path) or is_windows_path(expected_parts.path): path = PureWindowsPath(filter_windows_path(url_parts.path)) expected_path = PureWindowsPath(filter_windows_path(expected_parts.path)) else: path = PurePath(url_parts.path) expected_path = PurePath(expected_parts.path) self.assertEqual(path, expected_path, "%r: Paths differ." % url) def test_path_from_uri(self): _PurePath = xmlschema.resources._PurePath _PosixPurePath = xmlschema.resources._PurePosixPath _WindowsPurePath = xmlschema.resources._PureWindowsPath with self.assertRaises(ValueError) as ec: _PurePath.from_uri('') self.assertEqual(str(ec.exception), 'Empty URI provided!') path = _PurePath.from_uri('https://example.com/names/?name=foo') self.assertIsInstance(path, _PosixPurePath) self.assertEqual(str(path), '/names') path = _PosixPurePath.from_uri('file:///home/foo/names/?name=foo') self.assertIsInstance(path, _PosixPurePath) self.assertEqual(str(path), '/home/foo/names') path = _PosixPurePath.from_uri('file:///home/foo/names#foo') self.assertIsInstance(path, _PosixPurePath) self.assertEqual(str(path), '/home/foo/names') path = _PosixPurePath.from_uri('file:///home\\foo\\names#foo') self.assertIsInstance(path, _WindowsPurePath) self.assertTrue(path.as_posix().endswith('/home/foo/names')) path = _PosixPurePath.from_uri('file:///c:/home/foo/names/') self.assertIsInstance(path, _WindowsPurePath) self.assertEqual(str(path), r'c:\home\foo\names') self.assertEqual(path.as_uri(), 'file:///c:/home/foo/names') path = _PosixPurePath.from_uri('file:c:/home/foo/names/') self.assertIsInstance(path, _WindowsPurePath) self.assertEqual(str(path), r'c:\home\foo\names') self.assertEqual(path.as_uri(), 'file:///c:/home/foo/names') with self.assertRaises(ValueError) as ec: _PurePath.from_uri('file://c:/home/foo/names/') self.assertEqual(str(ec.exception), "Invalid URI 'file://c:/home/foo/names/'") @unittest.skipIf(platform.system() == 'Windows', "Run only on posix systems") def test_normalize_url_posix(self): url1 = "https://example.com/xsd/other_schema.xsd" self.check_url(normalize_url(url1, base_url="/path_my_schema/schema.xsd"), url1) parent_dir = os.path.dirname(os.getcwd()) self.check_url(normalize_url('../dir1/./dir2'), os.path.join(parent_dir, 'dir1/dir2')) self.check_url(normalize_url('../dir1/./dir2', '/home', keep_relative=True), 'file:///dir1/dir2') self.check_url(normalize_url('../dir1/./dir2', 'file:///home'), 'file:///dir1/dir2') self.check_url(normalize_url('other.xsd', 'file:///home'), 'file:///home/other.xsd') self.check_url(normalize_url('other.xsd', 'file:///home/'), 'file:///home/other.xsd') self.check_url(normalize_url('file:other.xsd', 'file:///home'), 'file:///home/other.xsd') cwd = os.getcwd() cwd_url = 'file://{}/'.format(cwd) if cwd.startswith('/') else 'file:///{}/'.format(cwd) self.check_url(normalize_url('other.xsd', keep_relative=True), 'file:other.xsd') self.check_url(normalize_url('file:other.xsd', keep_relative=True), 'file:other.xsd') self.check_url(normalize_url('file:other.xsd'), cwd_url + 'other.xsd') self.check_url(normalize_url('file:other.xsd', 'https://site/base', True), 'file:other.xsd') self.check_url(normalize_url('file:other.xsd', 'http://site/base'), cwd_url + 'other.xsd') self.check_url(normalize_url('dummy path.xsd'), cwd_url + 'dummy%20path.xsd') self.check_url(normalize_url('dummy path.xsd', 'http://site/base'), 'http://site/base/dummy%20path.xsd') self.check_url(normalize_url('dummy path.xsd', 'file://host/home/'), PurePath('//host/home/dummy path.xsd').as_uri()) url = "file:///c:/Downloads/file.xsd" self.check_url(normalize_url(url, base_url="file:///d:/Temp/"), url) def test_normalize_url_windows(self): win_abs_path1 = 'z:\\Dir_1_0\\Dir2-0\\schemas/XSD_1.0/XMLSchema.xsd' win_abs_path2 = 'z:\\Dir-1.0\\Dir-2_0\\' self.check_url(normalize_url(win_abs_path1), win_abs_path1) self.check_url(normalize_url('k:\\Dir3\\schema.xsd', win_abs_path1), 'file:///k:/Dir3/schema.xsd') self.check_url(normalize_url('k:\\Dir3\\schema.xsd', win_abs_path2), 'file:///k:/Dir3/schema.xsd') self.check_url(normalize_url('schema.xsd', win_abs_path2), 'file:///z:/Dir-1.0/Dir-2_0/schema.xsd') self.check_url(normalize_url('xsd1.0/schema.xsd', win_abs_path2), 'file:///z:/Dir-1.0/Dir-2_0/xsd1.0/schema.xsd') with self.assertRaises(ValueError) as ec: normalize_url('file:///\\k:\\Dir A\\schema.xsd') self.assertIn("Invalid URI", str(ec.exception)) def test_normalize_url_unc_paths__issue_246(self): url = PureWindowsPath(r'\\host\share\file.xsd').as_uri() self.assertNotEqual(normalize_url(r'\\host\share\file.xsd'), url) # file://host/share/file.xsd self.assertEqual(normalize_url(r'\\host\share\file.xsd'), url.replace('file://', 'file:////')) def test_normalize_url_unc_paths__issue_268(self,): unc_path = r'\\filer01\MY_HOME\dev\XMLSCHEMA\test.xsd' url = PureWindowsPath(unc_path).as_uri() self.assertEqual(str(PureWindowsPath(unc_path)), unc_path) self.assertEqual(url, 'file://filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') # Same UNC path as URI with the host inserted in path path. url_host_in_path = url.replace('file://', 'file:////') self.assertEqual(url_host_in_path, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') self.assertEqual(normalize_url(unc_path), url_host_in_path) with patch.object(os, 'name', 'nt'): self.assertEqual(os.name, 'nt') path = PurePath(unc_path) self.assertIs(path.__class__, PureWindowsPath) self.assertEqual(path.as_uri(), url) self.assertEqual(xmlschema.resources.os.name, 'nt') path = xmlschema.resources._PurePath(unc_path) self.assertIs(path.__class__, xmlschema.resources._PureWindowsPath) self.assertEqual(path.as_uri(), url_host_in_path) self.assertEqual(normalize_url(unc_path), url_host_in_path) with patch.object(os, 'name', 'posix'): self.assertEqual(os.name, 'posix') path = PurePath(unc_path) self.assertIs(path.__class__, PurePosixPath) self.assertEqual(str(path), unc_path) self.assertRaises(ValueError, path.as_uri) # Not recognized as UNC path self.assertEqual(xmlschema.resources.os.name, 'posix') path = xmlschema.resources._PurePath(unc_path) self.assertIs(path.__class__, xmlschema.resources._PurePosixPath) self.assertEqual(str(path), unc_path) self.assertNotEqual(path.as_uri(), url) self.assertEqual(normalize_url(unc_path), url_host_in_path) def test_normalize_url_with_base_unc_path(self,): base_unc_path = '\\\\filer01\\MY_HOME\\' base_url = PureWindowsPath(base_unc_path).as_uri() self.assertEqual(str(PureWindowsPath(base_unc_path)), base_unc_path) self.assertEqual(base_url, 'file://filer01/MY_HOME/') # Same UNC path as URI with the host inserted in path path. base_url_host_in_path = base_url.replace('file://', 'file:////') self.assertEqual(base_url_host_in_path, 'file:////filer01/MY_HOME/') self.assertEqual(normalize_url(base_unc_path), base_url_host_in_path) with patch.object(os, 'name', 'nt'): self.assertEqual(os.name, 'nt') path = PurePath('dir/file') self.assertIs(path.__class__, PureWindowsPath) url = normalize_url(r'dev\XMLSCHEMA\test.xsd', base_url=base_unc_path) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') url = normalize_url(r'dev\XMLSCHEMA\test.xsd', base_url=base_url) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') url = normalize_url(r'dev\XMLSCHEMA\test.xsd', base_url=base_url_host_in_path) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') with patch.object(os, 'name', 'posix'): self.assertEqual(os.name, 'posix') path = PurePath('dir/file') self.assertIs(path.__class__, PurePosixPath) url = normalize_url(r'dev\XMLSCHEMA\test.xsd', base_url=base_unc_path) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') url = normalize_url(r'dev/XMLSCHEMA/test.xsd', base_url=base_url) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') url = normalize_url(r'dev/XMLSCHEMA/test.xsd', base_url=base_url_host_in_path) self.assertEqual(url, 'file:////filer01/MY_HOME/dev/XMLSCHEMA/test.xsd') def test_normalize_url_slashes(self): # Issue #116 url = '//anaconda/envs/testenv/lib/python3.6/site-packages/xmlschema/validators/schemas/' if os.name == 'posix': self.assertEqual(normalize_url(url), pathlib.PurePath(url).as_uri()) else: # On Windows // is interpreted as a network share UNC path self.assertEqual(os.name, 'nt') self.assertEqual(normalize_url(url), pathlib.PurePath(url).as_uri().replace('file://', 'file:////')) self.assertRegex(normalize_url('/root/dir1/schema.xsd'), f'file://{DRIVE_REGEX}/root/dir1/schema.xsd') self.assertRegex(normalize_url('////root/dir1/schema.xsd'), f'file://{DRIVE_REGEX}/root/dir1/schema.xsd') self.assertRegex(normalize_url('dir2/schema.xsd', '////root/dir1'), f'file://{DRIVE_REGEX}/root/dir1/dir2/schema.xsd') self.assertEqual(normalize_url('//root/dir1/schema.xsd'), 'file:////root/dir1/schema.xsd') self.assertEqual(normalize_url('dir2/schema.xsd', '//root/dir1/'), f'file:////root/dir1/dir2/schema.xsd') self.assertEqual(normalize_url('dir2/schema.xsd', '//root/dir1'), f'file:////root/dir1/dir2/schema.xsd') def test_normalize_url_hash_character(self): url = normalize_url('issue #000.xml', 'file:///dir1/dir2/') self.assertRegex(url, f'file://{DRIVE_REGEX}/dir1/dir2/issue%20%23000.xml') url = normalize_url('data.xml', 'file:///dir1/dir2/issue%20001') self.assertRegex(url, f'file://{DRIVE_REGEX}/dir1/dir2/issue%20001/data.xml') url = normalize_url('data.xml', '/dir1/dir2/issue #002') self.assertRegex(url, f'{DRIVE_REGEX}/dir1/dir2/issue%20%23002/data.xml') def test_is_url_function(self): self.assertTrue(is_url(self.col_xsd_file)) self.assertFalse(is_url('http://example.com[')) self.assertTrue(is_url(b'http://example.com')) self.assertFalse(is_url(' \t<root/>')) self.assertFalse(is_url(b' <root/>')) self.assertFalse(is_url('line1\nline2')) self.assertFalse(is_url(None)) def test_is_local_url_function(self): self.assertTrue(is_local_url(self.col_xsd_file)) self.assertTrue(is_local_url(Path(self.col_xsd_file))) self.assertTrue(is_local_url('/home/user/')) self.assertFalse(is_local_url('<home/>')) self.assertTrue(is_local_url('/home/user/schema.xsd')) self.assertTrue(is_local_url(' /home/user/schema.xsd ')) self.assertTrue(is_local_url('C:\\Users\\foo\\schema.xsd')) self.assertTrue(is_local_url(' file:///home/user/schema.xsd')) self.assertFalse(is_local_url('http://example.com/schema.xsd')) self.assertTrue(is_local_url(b'/home/user/')) self.assertFalse(is_local_url(b'<home/>')) self.assertTrue(is_local_url(b'/home/user/schema.xsd')) self.assertTrue(is_local_url(b' /home/user/schema.xsd ')) self.assertTrue(is_local_url(b'C:\\Users\\foo\\schema.xsd')) self.assertTrue(is_local_url(b' file:///home/user/schema.xsd')) self.assertFalse(is_local_url(b'http://example.com/schema.xsd')) def test_is_remote_url_function(self): self.assertFalse(is_remote_url(self.col_xsd_file)) self.assertFalse(is_remote_url('/home/user/')) self.assertFalse(is_remote_url('<home/>')) self.assertFalse(is_remote_url('/home/user/schema.xsd')) self.assertFalse(is_remote_url(' file:///home/user/schema.xsd')) self.assertTrue(is_remote_url(' http://example.com/schema.xsd')) self.assertFalse(is_remote_url(b'/home/user/')) self.assertFalse(is_remote_url(b'<home/>')) self.assertFalse(is_remote_url(b'/home/user/schema.xsd')) self.assertFalse(is_remote_url(b' file:///home/user/schema.xsd')) self.assertTrue(is_remote_url(b' http://example.com/schema.xsd')) def test_url_path_is_file_function(self): self.assertTrue(url_path_is_file(self.col_xml_file)) self.assertTrue(url_path_is_file(normalize_url(self.col_xml_file))) self.assertFalse(url_path_is_file(self.col_dir)) self.assertFalse(url_path_is_file('http://example.com/')) with patch('platform.system', MagicMock(return_value="Windows")): self.assertFalse(url_path_is_file('file:///c:/Windows/unknown')) def test_normalize_locations_function(self): locations = normalize_locations( [('tns0', 'alpha'), ('tns1', 'http://example.com/beta')], base_url='/home/user' ) self.assertEqual(locations[0][0], 'tns0') self.assertRegex(locations[0][1], f'file://{DRIVE_REGEX}/home/user/alpha') self.assertEqual(locations[1][0], 'tns1') self.assertEqual(locations[1][1], 'http://example.com/beta') locations = normalize_locations( {'tns0': 'alpha', 'tns1': 'http://example.com/beta'}, base_url='/home/user' ) self.assertEqual(locations[0][0], 'tns0') self.assertRegex(locations[0][1], f'file://{DRIVE_REGEX}/home/user/alpha') self.assertEqual(locations[1][0], 'tns1') self.assertEqual(locations[1][1], 'http://example.com/beta') locations = normalize_locations( {'tns0': ['alpha', 'beta'], 'tns1': 'http://example.com/beta'}, base_url='/home/user' ) self.assertEqual(locations[0][0], 'tns0') self.assertRegex(locations[0][1], f'file://{DRIVE_REGEX}/home/user/alpha') self.assertEqual(locations[1][0], 'tns0') self.assertRegex(locations[1][1], f'file://{DRIVE_REGEX}/home/user/beta') self.assertEqual(locations[2][0], 'tns1') self.assertEqual(locations[2][1], 'http://example.com/beta') locations = normalize_locations( {'tns0': 'alpha', 'tns1': 'http://example.com/beta'}, keep_relative=True ) self.assertListEqual(locations, [('tns0', 'file:alpha'), ('tns1', 'http://example.com/beta')]) def test_fetch_resource_function(self): with self.assertRaises(ValueError) as ctx: fetch_resource('') self.assertIn('argument must contain a not empty string', str(ctx.exception)) wrong_path = casepath('resources/dummy_file.txt') self.assertRaises(XMLResourceError, fetch_resource, wrong_path) wrong_path = casepath('/home/dummy_file.txt') self.assertRaises(XMLResourceError, fetch_resource, wrong_path) right_path = casepath('resources/dummy file.txt') self.assertTrue(fetch_resource(right_path).endswith('dummy%20file.txt')) right_path = Path(casepath('resources/dummy file.txt')).relative_to(os.getcwd()) self.assertTrue(fetch_resource(str(right_path), '/home').endswith('dummy%20file.txt')) with self.assertRaises(XMLResourceError): fetch_resource(str(right_path.parent.joinpath('dummy_file.txt')), '/home') ambiguous_path = casepath('resources/dummy file #2.txt') self.assertTrue(fetch_resource(ambiguous_path).endswith('dummy%20file%20%232.txt')) with urlopen(fetch_resource(ambiguous_path)) as res: self.assertEqual(res.read(), b'DUMMY CONTENT') def test_fetch_namespaces_function(self): self.assertFalse(fetch_namespaces(casepath('resources/malformed.xml'))) def test_fetch_schema_locations(self): locations = fetch_schema_locations(self.col_xml_file) self.check_url(locations[0], self.col_xsd_file) self.assertEqual(locations[1][0][0], 'http://example.com/ns/collection') self.check_url(locations[1][0][1], self.col_xsd_file) self.check_url(fetch_schema(self.vh_xml_file), self.vh_xsd_file) with self.assertRaises(ValueError) as ctx: fetch_schema_locations('<empty/>') self.assertIn('does not contain any schema location hint', str(ctx.exception)) # Tests on XMLResource instances def test_xml_resource_representation(self): resource = XMLResource(self.vh_xml_file) self.assertTrue(str(resource).startswith( "XMLResource(root=<Element '{http://example.com/vehicles}vehicles'" )) def test_xml_resource_from_url(self): resource = XMLResource(self.vh_xml_file, lazy=True) self.assertEqual(resource.source, self.vh_xml_file) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.check_url(resource.url, self.vh_xml_file) self.assertTrue(resource.filepath.endswith('vehicles.xml')) self.assertIsNone(resource.text) with self.assertRaises(XMLResourceError) as ctx: resource.load() self.assertIn('cannot load a lazy resource', str(ctx.exception)) self.assertIsNone(resource.text) resource = XMLResource(self.vh_xml_file, lazy=False) self.assertEqual(resource.source, self.vh_xml_file) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.check_url(resource.url, self.vh_xml_file) self.assertIsNone(resource.text) resource.load() self.assertTrue(resource.text.startswith('<?xml')) resource = XMLResource(self.vh_xml_file, lazy=False) resource._url = resource._url[:-12] + 'unknown.xml' with self.assertRaises(XMLResourceError): resource.load() def test_xml_resource_from_url_in_bytes(self): resource = XMLResource(self.vh_xml_file.encode('utf-8'), lazy=False) self.assertEqual(resource.source, self.vh_xml_file.encode('utf-8')) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.check_url(resource.url, self.vh_xml_file) self.assertIsNone(resource.text) resource.load() self.assertTrue(resource.text.startswith('<?xml')) def test_xml_resource_from_path(self): path = Path(self.vh_xml_file) resource = XMLResource(path, lazy=True) self.assertIs(resource.source, path) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.check_url(resource.url, path.as_uri()) self.assertTrue(resource.filepath.endswith('vehicles.xml')) self.assertIsNone(resource.text) with self.assertRaises(XMLResourceError) as ctx: resource.load() self.assertIn('cannot load a lazy resource', str(ctx.exception)) self.assertIsNone(resource.text) resource = XMLResource(path, lazy=False) self.assertEqual(resource.source, path) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.check_url(resource.url, path.as_uri()) self.assertIsNone(resource.text) resource.load() self.assertTrue(resource.text.startswith('<?xml')) resource = XMLResource(path, lazy=False) resource._url = resource._url[:-12] + 'unknown.xml' with self.assertRaises(XMLResourceError): resource.load() def test_xml_resource_from_element_tree(self): vh_etree = ElementTree.parse(self.vh_xml_file) vh_root = vh_etree.getroot() resource = XMLResource(vh_etree) self.assertEqual(resource.source, vh_etree) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.assertIsNone(resource.url) self.assertIsNone(resource.filepath) self.assertIsNone(resource.text) resource.load() self.assertIsNone(resource.text) resource = XMLResource(vh_root) self.assertEqual(resource.source, vh_root) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.assertIsNone(resource.url) self.assertIsNone(resource.filepath) self.assertIsNone(resource.text) resource.load() self.assertIsNone(resource.text) @unittest.skipIf(lxml_etree is None, "Skip: lxml is not available.") def test_xml_resource_from_lxml(self): vh_etree = lxml_etree.parse(self.vh_xml_file) vh_root = vh_etree.getroot() resource = XMLResource(vh_etree) self.assertEqual(resource.source, vh_etree) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.assertIsNone(resource.url) self.assertIsNone(resource.filepath) self.assertIsNone(resource.text) resource.load() self.assertIsNone(resource.text) resource = XMLResource(vh_root) self.assertEqual(resource.source, vh_root) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.assertIsNone(resource.url) self.assertIsNone(resource.filepath) self.assertIsNone(resource.text) resource.load() self.assertIsNone(resource.text) xml_text = resource.get_text() self.assertIn('<vh:vehicles ', xml_text) self.assertIn('<!-- Comment -->', xml_text) self.assertIn('</vh:vehicles>', xml_text) def test_xml_resource_from_resource(self): xml_file = urlopen('file://{}'.format(add_leading_slash(self.vh_xml_file))) try: resource = XMLResource(xml_file, lazy=False) self.assertEqual(resource.source, xml_file) self.assertEqual(resource.root.tag, '{http://example.com/vehicles}vehicles') self.assertIsNone(resource.url) self.assertIsNone(resource.text) resource.load() self.assertTrue(resource.text.startswith('<?xml')) self.assertFalse(xml_file.closed) finally: xml_file.close() with open(self.vh_xml_file) as fp: resource = XMLResource(fp) self.assertIsNone(resource.text) with self.assertRaises(XMLResourceError): resource.load() def test_xml_resource_from_file(self): with open(self.vh_xsd_file) as schema_file: resource = XMLResource(schema_file, lazy=False) self.assertEqual(resource.source, schema_file) self.assertEqual(resource.root.tag, '{http://www.w3.org/2001/XMLSchema}schema') self.assertIsNone(resource.url) self.assertIsNone(resource.text) resource.load() self.assertTrue(resource.text.startswith('<xs:schema')) self.assertFalse(schema_file.closed) for _ in resource.iter(): pass self.assertFalse(schema_file.closed) for _ in resource.iter_depth(): pass self.assertFalse(schema_file.closed) with open(self.vh_xsd_file) as schema_file: resource = XMLResource(schema_file, lazy=True) self.assertEqual(resource.source, schema_file) self.assertEqual(resource.root.tag, '{http://www.w3.org/2001/XMLSchema}schema') self.assertIsNone(resource.url) self.assertIsNone(resource.text) with self.assertRaises(XMLResourceError) as ctx: resource.load() self.assertEqual("cannot load a lazy resource", str(ctx.exception)) self.assertFalse(schema_file.closed) for _ in resource.iter(): pass self.assertFalse(schema_file.closed) for _ in resource.iter_depth(): pass self.assertFalse(schema_file.closed) def test_xml_resource_from_string(self): with open(self.vh_xsd_file) as schema_file: schema_text = schema_file.read() resource = XMLResource(schema_text, lazy=False) self.assertEqual(resource.source, schema_text) self.assertEqual(resource.root.tag, '{http://www.w3.org/2001/XMLSchema}schema') self.assertIsNone(resource.url) self.assertTrue(resource.text.startswith('<xs:schema')) invalid_xml = '<tns0:root>missing namespace declaration</tns0:root>' with self.assertRaises(ElementTree.ParseError) as ctx: XMLResource(invalid_xml) self.assertEqual(str(ctx.exception), 'unbound prefix: line 1, column 0') def test_xml_resource_from_string_io(self): with open(self.vh_xsd_file) as schema_file: schema_text = schema_file.read() schema_file = StringIO(schema_text) resource = XMLResource(schema_file) self.assertEqual(resource.source, schema_file) self.assertEqual(resource.root.tag, '{http://www.w3.org/2001/XMLSchema}schema') self.assertIsNone(resource.url) self.assertTrue(resource.text.startswith('<xs:schema')) schema_file = StringIO(schema_text) resource = XMLResource(schema_file, lazy=False) self.assertEqual(resource.source, schema_file) self.assertEqual(resource.root.tag, '{http://www.w3.org/2001/XMLSchema}schema') self.assertIsNone(resource.url) self.assertTrue(resource.text.startswith('<xs:schema')) def test_xml_resource_from_bytes_io(self): source = '<?xml version="1.0" encoding="iso-8859-1"?>\n<a>ç</a>' resource = XMLResource(BytesIO(source.encode('iso-8859-1'))) self.assertIsNone(resource.text) resource.load() self.assertEqual(resource.text, source) def test_xml_resource_from_malformed_source(self): # related to issue #224 malformed_xml_file = casepath('resources/malformed.xml') with self.assertRaises(ElementTree.ParseError): XMLResource(malformed_xml_file) with self.assertRaises(ElementTree.ParseError): XMLResource(malformed_xml_file, defuse='always') # the incremental parser does not found the incomplete root before the end resource = XMLResource(malformed_xml_file, lazy=True) self.assertEqual(resource.root.tag, 'malformed_xml_file') resource = XMLResource('<malformed_xml_file>>', lazy=True) self.assertEqual(resource.root.tag, 'malformed_xml_file') with self.assertRaises(ElementTree.ParseError): XMLResource('<malformed_xml_file<>', lazy=True) def test_xml_resource_from_wrong_arguments(self): self.assertRaises(TypeError, XMLResource, [b'<UNSUPPORTED_DATA_TYPE/>']) with self.assertRaises(TypeError) as ctx: XMLResource('<root/>', base_url=[b'/home']) self.assertIn(' ', str(ctx.exception)) def test_xml_resource_namespace(self): resource = XMLResource(self.vh_xml_file) self.assertEqual(resource.namespace, 'http://example.com/vehicles') resource = XMLResource(self.vh_xsd_file) self.assertEqual(resource.namespace, 'http://www.w3.org/2001/XMLSchema') resource = XMLResource(self.col_xml_file) self.assertEqual(resource.namespace, 'http://example.com/ns/collection') self.assertEqual(XMLResource('<A/>').namespace, '') def test_xml_resource_update_nsmap_method(self): resource = XMLResource(self.vh_xml_file) nsmap = {} resource._update_nsmap(nsmap, 'xs', XSD_NAMESPACE) self.assertEqual(nsmap, {'xs': XSD_NAMESPACE}) resource._update_nsmap(nsmap, 'xs', XSD_NAMESPACE) self.assertEqual(nsmap, {'xs': XSD_NAMESPACE}) resource._update_nsmap(nsmap, 'tns0', 'http://example.com/ns') self.assertEqual(nsmap, {'xs': XSD_NAMESPACE, 'tns0': 'http://example.com/ns'}) resource._update_nsmap(nsmap, 'xs', 'http://example.com/ns') self.assertEqual(nsmap, {'xs': XSD_NAMESPACE, 'xs0': 'http://example.com/ns', 'tns0': 'http://example.com/ns'}) resource._update_nsmap(nsmap, 'xs', 'http://example.com/ns') self.assertEqual(nsmap, {'xs': XSD_NAMESPACE, 'xs0': 'http://example.com/ns', 'tns0': 'http://example.com/ns'}) resource._update_nsmap(nsmap, 'xs', 'http://example.com/ns2') self.assertEqual(nsmap, {'xs': XSD_NAMESPACE, 'xs0': 'http://example.com/ns', 'xs1': 'http://example.com/ns2', 'tns0': 'http://example.com/ns'}) def test_xml_resource_access(self): resource = XMLResource(self.vh_xml_file) base_url = resource.base_url XMLResource(self.vh_xml_file, allow='local') XMLResource( self.vh_xml_file, base_url=os.path.dirname(self.vh_xml_file), allow='sandbox' ) with self.assertRaises(XMLResourceError) as ctx: XMLResource(self.vh_xml_file, allow='remote') self.assertTrue(str(ctx.exception).startswith("block access to local resource")) with self.assertRaises(URLError): XMLResource("https://xmlschema.test/vehicles.xsd", allow='remote') with self.assertRaises(XMLResourceError) as ctx: XMLResource("https://xmlschema.test/vehicles.xsd", allow='local') self.assertEqual(str(ctx.exception), "block access to remote resource https://xmlschema.test/vehicles.xsd") with self.assertRaises(XMLResourceError) as ctx: XMLResource("https://xmlschema.test/vehicles.xsd", allow='sandbox') self.assertEqual(str(ctx.exception), "block access to files out of sandbox requires 'base_url' to be set") with self.assertRaises(XMLResourceError) as ctx: XMLResource("/tmp/vehicles.xsd", allow='sandbox') self.assertEqual( str(ctx.exception), "block access to files out of sandbox requires 'base_url' to be set", ) source = "/tmp/vehicles.xsd" with self.assertRaises(XMLResourceError) as ctx: XMLResource(source, base_url=base_url, allow='sandbox') self.assertEqual( str(ctx.exception), "block access to out of sandbox file {}".format(normalize_url(source)), ) with self.assertRaises(TypeError) as ctx: XMLResource("https://xmlschema.test/vehicles.xsd", allow=None) self.assertEqual(str(ctx.exception), "invalid type <class 'NoneType'> for argument 'allow'") with self.assertRaises(ValueError) as ctx: XMLResource("https://xmlschema.test/vehicles.xsd", allow='any') self.assertEqual(str(ctx.exception), "'allow' argument: 'any' is not a security mode") with self.assertRaises(XMLResourceError) as ctx: XMLResource(self.vh_xml_file, allow='none') self.assertTrue(str(ctx.exception).startswith('block access to resource')) self.assertTrue(str(ctx.exception).endswith('vehicles.xml')) with open(self.vh_xml_file) as fp: resource = XMLResource(fp, allow='none') self.assertIsInstance(resource, XMLResource) self.assertIsNone(resource.url) with open(self.vh_xml_file) as fp: resource = XMLResource(fp.read(), allow='none') self.assertIsInstance(resource, XMLResource) self.assertIsNone(resource.url) with open(self.vh_xml_file) as fp: resource = XMLResource(StringIO(fp.read()), allow='none') self.assertIsInstance(resource, XMLResource) self.assertIsNone(resource.url) def test_xml_resource_defuse(self): resource = XMLResource(self.vh_xml_file, defuse='never', lazy=True) self.assertEqual(resource.defuse, 'never') self.assertRaises(ValueError, XMLResource, self.vh_xml_file, defuse='all') self.assertRaises(TypeError, XMLResource, self.vh_xml_file, defuse=None) self.assertIsInstance(resource.root, etree_element) resource = XMLResource(self.vh_xml_file, defuse='always', lazy=True) self.assertIsInstance(resource.root, py_etree_element) xml_file = casepath('resources/with_entity.xml') self.assertIsInstance(XMLResource(xml_file, lazy=True), XMLResource) with self.assertRaises(ElementTree.ParseError): XMLResource(xml_file, defuse='always', lazy=True) xml_file = casepath('resources/unused_external_entity.xml') self.assertIsInstance(XMLResource(xml_file, lazy=True), XMLResource) with self.assertRaises(ElementTree.ParseError): XMLResource(xml_file, defuse='always', lazy=True) def test_xml_resource_defuse_other_source_types(self): xml_file = casepath('resources/external_entity.xml') self.assertIsInstance(XMLResource(xml_file, lazy=True), XMLResource) with self.assertRaises(ElementTree.ParseError): XMLResource(xml_file, defuse='always', lazy=True) with self.assertRaises(ElementTree.ParseError): XMLResource(xml_file, defuse='always', lazy=False) with self.assertRaises(ElementTree.ParseError): XMLResource(xml_file, defuse='always', lazy=True) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(fp, defuse='always', lazy=False) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(fp.read(), defuse='always', lazy=False) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(StringIO(fp.read()), defuse='always', lazy=False) def test_xml_resource_defuse_nonlocal(self): xml_file = casepath('resources/external_entity.xml') resource = XMLResource(xml_file, defuse='nonlocal', lazy=True) self.assertIsInstance(resource, XMLResource) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(fp, defuse='nonlocal', lazy=True) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(fp.read(), defuse='nonlocal', lazy=True) with self.assertRaises(ElementTree.ParseError): with open(xml_file) as fp: XMLResource(StringIO(fp.read()), defuse='nonlocal', lazy=True) def test_xml_resource_timeout(self): resource = XMLResource(self.vh_xml_file, timeout=30) self.assertEqual(resource.timeout, 30) self.assertRaises(TypeError, XMLResource, self.vh_xml_file, timeout='100') self.assertRaises(ValueError, XMLResource, self.vh_xml_file, timeout=0) def test_xml_resource_laziness(self): resource = XMLResource(self.vh_xml_file, lazy=True) self.assertTrue(resource.is_lazy()) resource = XMLResource(self.vh_xml_file, lazy=False) self.assertFalse(resource.is_lazy()) resource = XMLResource(self.vh_xml_file, lazy=1) self.assertTrue(resource.is_lazy()) resource = XMLResource(self.vh_xml_file, lazy=2) self.assertTrue(resource.is_lazy()) resource = XMLResource(self.vh_xml_file, lazy=0) self.assertFalse(resource.is_lazy()) with self.assertRaises(ValueError): XMLResource(self.vh_xml_file, lazy=-1) with self.assertRaises(TypeError): XMLResource(self.vh_xml_file, lazy='1') def test_xml_resource_base_url(self): resource = XMLResource(self.vh_xml_file) base_url = resource.base_url self.assertEqual(base_url, XMLResource(self.vh_xml_file, '/other').base_url) with open(self.vh_xml_file) as fp: self.assertIsNone(XMLResource(fp.read()).base_url) with open(self.vh_xml_file) as fp: resource = XMLResource(fp.read(), base_url='/foo') self.assertEqual(resource.base_url, '/foo') base_url = Path(self.vh_xml_file).parent resource = XMLResource('vehicles.xml', base_url) self.assertEqual(resource.base_url, base_url.as_uri()) resource = XMLResource('vehicles.xml', str(base_url)) self.assertEqual(resource.base_url, base_url.as_uri()) resource = XMLResource('vehicles.xml', str(base_url).encode()) self.assertEqual(resource.base_url, base_url.as_uri()) self.assertEqual(resource.base_url, base_url.as_uri()) with self.assertRaises(TypeError): XMLResource(self.vh_xml_file, base_url=False) with self.assertRaises(ValueError): XMLResource(self.vh_xml_file, base_url='<root/>') with self.assertRaises(ValueError): XMLResource(self.vh_xml_file, base_url=b'<root/>') def test_xml_resource_is_local(self): resource = XMLResource(self.vh_xml_file) self.assertTrue(resource.is_local()) def test_xml_resource_is_remote(self): resource = XMLResource(self.vh_xml_file) self.assertFalse(resource.is_remote()) def test_xml_resource_is_loaded(self): resource = XMLResource(self.vh_xml_file, lazy=False) self.assertFalse(resource.is_loaded()) resource.load() self.assertTrue(resource.is_loaded()) def test_xml_resource__lazy_iterparse(self): resource = XMLResource(self.vh_xml_file, lazy=True) self.assertEqual(resource.defuse, 'remote') for _, elem in resource._lazy_iterparse(self.col_xml_file): self.assertTrue(is_etree_element(elem)) nsmap = [] for _, elem in resource._lazy_iterparse(self.col_xml_file, nsmap=nsmap): self.assertTrue(is_etree_element(elem)) self.assertListEqual( nsmap, [('col', 'http://example.com/ns/collection'), ('xsi', 'http://www.w3.org/2001/XMLSchema-instance')]) resource._defuse = 'always' for _, elem in resource._lazy_iterparse(self.col_xml_file): self.assertTrue(is_etree_element(elem)) def test_xml_resource__iterparse(self): resource = XMLResource(self.vh_xml_file, lazy=False) self.assertEqual(resource.defuse, 'remote') with open(self.col_xml_file) as fp: resource._parse(fp) self.assertTrue(is_etree_element(resource.root)) resource._defuse = 'always' with open(self.col_xml_file) as fp: resource._parse(fp) self.assertTrue(is_etree_element(resource.root)) with urlopen(resource.url) as fp: resource._parse(fp) self.assertTrue(is_etree_element(resource.root)) def test_xml_resource_tostring(self): resource = XMLResource(self.vh_xml_file) self.assertTrue(resource.tostring().startswith('<vh:vehicles')) resource = XMLResource(self.vh_xml_file, lazy=True) with self.assertRaises(XMLResourceError) as ctx: resource.tostring() self.assertEqual("cannot serialize a lazy resource", str(ctx.exception)) def test_xml_resource_open(self): resource = XMLResource(self.vh_xml_file) xml_file = resource.open() self.assertIsNot(xml_file, resource.source) data = xml_file.read().decode('utf-8') self.assertTrue(data.startswith('<?xml ')) xml_file.close() resource._url = 'file:not-a-file' with self.assertRaises(XMLResourceError): resource.open() resource = XMLResource('<A/>') self.assertRaises(XMLResourceError, resource.open) resource = XMLResource(source=open(self.vh_xml_file)) xml_file = resource.open() self.assertIs(xml_file, resource.source) xml_file.close() def test_xml_resource_seek(self): resource = XMLResource(self.vh_xml_file) self.assertIsNone(resource.seek(0)) self.assertIsNone(resource.seek(1)) xml_file = open(self.vh_xml_file) resource = XMLResource(source=xml_file) self.assertEqual(resource.seek(0), 0) self.assertEqual(resource.seek(1), 1) xml_file.close() def test_xml_resource_close(self): resource = XMLResource(self.vh_xml_file) resource.close() xml_file = resource.open() try: self.assertTrue(callable(xml_file.read)) finally: resource.close() with open(self.vh_xml_file) as xml_file: resource = XMLResource(source=xml_file) resource.close() with self.assertRaises(XMLResourceError): resource.open() with open(self.vh_xml_file) as xml_file: resource = XMLResource(xml_file) with self.assertRaises(XMLResourceError): resource.load() # I/O operation on closed file def test_xml_resource_iter(self): resource = XMLResource(XMLSchema.meta_schema.source.url) self.assertFalse(resource.is_lazy()) lazy_resource = XMLResource(XMLSchema.meta_schema.source.url, lazy=True) self.assertTrue(lazy_resource.is_lazy()) tags = [x.tag for x in resource.iter()] self.assertEqual(len(tags), 1390) self.assertEqual(tags[0], '{%s}schema' % XSD_NAMESPACE) lazy_tags = [x.tag for x in lazy_resource.iter()] self.assertEqual(len(lazy_tags), 1390) self.assertEqual(lazy_tags[-1], '{%s}schema' % XSD_NAMESPACE) self.assertNotEqual(tags, lazy_tags) tags = [x.tag for x in resource.iter('{%s}complexType' % XSD_NAMESPACE)] self.assertEqual(len(tags), 56) self.assertEqual(tags[0], '{%s}complexType' % XSD_NAMESPACE) self.assertListEqual( tags, [x.tag for x in lazy_resource.iter('{%s}complexType' % XSD_NAMESPACE)] ) def test_xml_resource_iter_depth(self): resource = XMLResource(XMLSchema.meta_schema.source.url) self.assertFalse(resource.is_lazy()) lazy_resource = XMLResource(XMLSchema.meta_schema.source.url, lazy=True) self.assertTrue(lazy_resource.is_lazy()) # Note: Element change with lazy resource so compare only tags nsmap = [] tags = [x.tag for x in resource.iter_depth(nsmap=nsmap)] self.assertEqual(len(tags), 1) self.assertEqual(tags[0], '{%s}schema' % XSD_NAMESPACE) self.assertListEqual( nsmap, [('xs', 'http://www.w3.org/2001/XMLSchema'), ('hfp', 'http://www.w3.org/2001/XMLSchema-hasFacetAndProperty')]) lazy_tags = [x.tag for x in lazy_resource.iter_depth()] self.assertEqual(len(lazy_tags), 156) self.assertEqual(lazy_tags[0], '{%s}annotation' % XSD_NAMESPACE) self.assertEqual(lazy_tags[-1], '{%s}element' % XSD_NAMESPACE) lazy_tags = [x.tag for x in lazy_resource.iter_depth(mode=2)] self.assertListEqual(tags, lazy_tags) lazy_tags = [x.tag for x in lazy_resource.iter_depth(mode=1)] self.assertEqual(len(lazy_tags), 156) lazy_tags = [x.tag for x in lazy_resource.iter_depth(mode=3)] self.assertEqual(len(lazy_tags), 157) self.assertEqual(tags[0], lazy_tags[-1]) lazy_tags = [x.tag for x in lazy_resource.iter_depth(mode=4)] self.assertEqual(len(lazy_tags), 158) self.assertEqual(tags[0], lazy_tags[0]) self.assertEqual(tags[0], lazy_tags[-1]) with self.assertRaises(ValueError) as ctx: _ = [x.tag for x in lazy_resource.iter_depth(mode=5)] self.assertEqual("invalid argument mode=5", str(ctx.exception)) source = StringIO('<a xmlns:tns0="http://example.com/ns0"><b1>' ' <c1 xmlns:tns1="http://example.com/ns1"/>' ' <c2 xmlns:tns2="http://example.com/ns2" x="2"/>' '</b1><b2><c3><d1/></c3></b2></a>') resource = XMLResource(source, lazy=3) nsmap = [] ancestors = [] self.assertIs(next(resource.iter_depth(nsmap=nsmap, ancestors=ancestors)), resource.root[1][0][0]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0')]) self.assertListEqual(ancestors, [resource.root, resource.root[1], resource.root[1][0]]) def test_xml_resource_iterfind(self): namespaces = {'xs': XSD_NAMESPACE} resource = XMLResource(XMLSchema.meta_schema.source.url) self.assertFalse(resource.is_lazy()) lazy_resource = XMLResource(XMLSchema.meta_schema.source.url, lazy=True) self.assertTrue(lazy_resource.is_lazy()) tags = [x.tag for x in resource.iterfind(path='.')] self.assertEqual(len(tags), 1) self.assertEqual(tags[0], '{%s}schema' % XSD_NAMESPACE) lazy_tags = [x.tag for x in lazy_resource.iterfind(path='.')] self.assertListEqual(tags, lazy_tags) tags = [x.tag for x in resource.iterfind(path='*')] self.assertEqual(len(tags), 156) self.assertEqual(tags[0], '{%s}annotation' % XSD_NAMESPACE) lazy_tags = [x.tag for x in lazy_resource.iterfind(path='*')] self.assertListEqual(tags, lazy_tags) tags = [x.tag for x in resource.iterfind('xs:complexType', namespaces)] self.assertEqual(len(tags), 35) self.assertTrue(all(t == '{%s}complexType' % XSD_NAMESPACE for t in tags)) lazy_tags = [x.tag for x in lazy_resource.iterfind('xs:complexType', namespaces)] self.assertListEqual(tags, lazy_tags) tags = [x.tag for x in resource.iterfind('. /. / xs:complexType', namespaces)] self.assertEqual(len(tags), 35) self.assertTrue(all(t == '{%s}complexType' % XSD_NAMESPACE for t in tags)) lazy_tags = [ x.tag for x in lazy_resource.iterfind('. /. / xs:complexType', namespaces) ] self.assertListEqual(tags, lazy_tags) def test_xml_resource_find(self): root = ElementTree.XML('<a><b1><c1/><c2 x="2"/></b1><b2/></a>') resource = XMLResource(root) self.assertIs(resource.find('*/c2'), root[0][1]) self.assertIsNone(resource.find('*/c3')) resource = XMLResource('<a><b1>' ' <c1 xmlns:tns1="http://example.com/ns1"/>' ' <c2 xmlns:tns2="http://example.com/ns2" x="2"/>' '</b1><b2/></a>') nsmap = [] self.assertIs(resource.find('*/c2', nsmap=nsmap), resource.root[0][1]) self.assertListEqual(nsmap, [('tns2', 'http://example.com/ns2')]) nsmap = [] self.assertEqual(resource.find('*/c2/@x', nsmap=nsmap), '2') self.assertListEqual(nsmap, []) nsmap = [] ancestors = [] self.assertIs(resource.find('*/c2', nsmap=nsmap, ancestors=ancestors), resource.root[0][1]) self.assertListEqual(nsmap, [('tns2', 'http://example.com/ns2')]) self.assertListEqual(ancestors, [resource.root, resource.root[0]]) nsmap = [] ancestors = [] self.assertEqual(resource.find('*/c2/@x', nsmap=nsmap, ancestors=ancestors), '2') self.assertListEqual(nsmap, []) self.assertListEqual(ancestors, []) nsmap = [] ancestors = [] self.assertIs(resource.find('.', nsmap=nsmap, ancestors=ancestors), resource.root) self.assertListEqual(nsmap, []) self.assertListEqual(ancestors, []) nsmap = [] ancestors = [] self.assertIsNone(resource.find('b3', nsmap=nsmap, ancestors=ancestors)) self.assertListEqual(nsmap, []) self.assertListEqual(ancestors, []) def test_xml_resource_lazy_find(self): source = StringIO('<a><b1><c1/><c2 x="2"/></b1><b2/></a>') resource = XMLResource(source, lazy=True) self.assertIs(resource.find('*/c2'), resource.root[0][1]) source = StringIO('<a xmlns:tns0="http://example.com/ns0"><b1>' ' <c1 xmlns:tns1="http://example.com/ns1"/>' ' <c2 xmlns:tns2="http://example.com/ns2" x="2"/>' '</b1><b2><c3><d1/></c3></b2></a>') resource = XMLResource(source, lazy=True) nsmap = [] ancestors = [] self.assertIs(resource.find('*/c2', nsmap=nsmap, ancestors=ancestors), resource.root[0][1]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0'), ('tns2', 'http://example.com/ns2')]) self.assertListEqual(ancestors, [resource.root, resource.root[0]]) nsmap = [] ancestors = [] self.assertIs(resource.find('*/c3', nsmap=nsmap, ancestors=ancestors), resource.root[1][0]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0')]) self.assertListEqual(ancestors, [resource.root, resource.root[1]]) nsmap = [] ancestors = [] self.assertIs(resource.find('*/c3/d1', nsmap=nsmap, ancestors=ancestors), resource.root[1][0][0]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0')]) self.assertListEqual(ancestors, [resource.root, resource.root[1], resource.root[1][0]]) nsmap = [] ancestors = [] self.assertIs(resource.find('*', nsmap=nsmap, ancestors=ancestors), resource.root[0]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0')]) self.assertListEqual(ancestors, [resource.root]) nsmap = [] ancestors = [] self.assertIsNone(resource.find('/b1', nsmap=nsmap, ancestors=ancestors)) self.assertListEqual(nsmap, []) self.assertListEqual(ancestors, []) source.seek(0) resource = XMLResource(source, lazy=2) nsmap = [] ancestors = [] self.assertIs(resource.find('*/c2', nsmap=nsmap, ancestors=ancestors), resource.root[0][1]) self.assertListEqual(nsmap, [('tns0', 'http://example.com/ns0'), ('tns2', 'http://example.com/ns2')]) self.assertListEqual(ancestors, [resource.root, resource.root[0]]) def test_xml_resource_findall(self): root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/></a>') resource = XMLResource(root) self.assertListEqual(resource.findall('*/*'), root[0][:]) self.assertListEqual(resource.findall('*/c3'), []) def test_xml_resource_nsmap_tracking(self): xsd_file = casepath('examples/collection/collection4.xsd') resource = XMLResource(xsd_file) root = resource.root nsmap = [] for elem in resource.iter(nsmap=nsmap): if elem is root[2][0] or elem in root[2][0]: self.assertEqual(dict(nsmap), {'xs': 'http://www.w3.org/2001/XMLSchema', '': 'http://www.w3.org/2001/XMLSchema'}) else: self.assertEqual(dict(nsmap), {'xs': 'http://www.w3.org/2001/XMLSchema', '': 'http://example.com/ns/collection'}) nsmap.clear() resource._nsmap.clear() resource._nsmap[resource._root] = [] for _ in resource.iter(nsmap=nsmap): self.assertEqual(nsmap, []) nsmap.clear() if lxml_etree is not None: tree = lxml_etree.parse(xsd_file) resource = XMLResource(tree) root = resource.root for elem in resource.iter(nsmap=nsmap): if callable(elem.tag): continue if elem is root[2][0] or elem in root[2][0]: self.assertEqual(dict(nsmap), {'xs': 'http://www.w3.org/2001/XMLSchema', '': 'http://www.w3.org/2001/XMLSchema'}) else: self.assertEqual(dict(nsmap), {'xs': 'http://www.w3.org/2001/XMLSchema', '': 'http://example.com/ns/collection'}) nsmap = {} resource = XMLResource(xsd_file, lazy=True) root = elem = resource.root for elem in resource.iter(nsmap=nsmap): try: if elem is resource.root[2][0] or elem in resource.root[2][0]: self.assertEqual(nsmap['default'], 'http://www.w3.org/2001/XMLSchema') self.assertEqual(nsmap[''], 'http://example.com/ns/collection') except IndexError: self.assertEqual(nsmap[''], 'http://example.com/ns/collection') self.assertIs(elem, resource.root) self.assertIsNot(root, resource.root) def test_xml_resource_get_namespaces(self): with open(self.vh_xml_file) as schema_file: resource = XMLResource(schema_file) self.assertIsNone(resource.url) self.assertEqual(set(resource.get_namespaces().keys()), {'vh', 'xsi'}) self.assertFalse(schema_file.closed) with open(self.vh_xsd_file) as schema_file: resource = XMLResource(schema_file) self.assertIsNone(resource.url) self.assertEqual(set(resource.get_namespaces().keys()), {'xs', 'vh'}) self.assertFalse(schema_file.closed) resource = XMLResource(self.col_xml_file) self.assertEqual(resource.url, normalize_url(self.col_xml_file)) self.assertEqual(set(resource.get_namespaces().keys()), {'col', 'xsi'}) resource = XMLResource(self.col_xsd_file) self.assertEqual(resource.url, normalize_url(self.col_xsd_file)) self.assertEqual(set(resource.get_namespaces().keys()), {'', 'xs'}) resource = XMLResource("""<?xml version="1.0" ?> <root xmlns="tns1"> <tns:elem1 xmlns:tns="tns1" xmlns="unknown"/> </root>""", lazy=False) self.assertEqual(set(resource.get_namespaces(root_only=False).keys()), {'', 'tns', 'default'}) resource = XMLResource("""<?xml version="1.0" ?> <root xmlns:tns="tns1"> <tns:elem1 xmlns:tns="tns1" xmlns="unknown"/> </root>""", lazy=False) self.assertEqual(set(resource.get_namespaces(root_only=False).keys()), {'default', 'tns'}) self.assertEqual(resource.get_namespaces(root_only=True).keys(), {'tns'}) resource = XMLResource("""<?xml version="1.0" ?> <root xmlns:tns="tns1"> <tns:elem1 xmlns:tns="tns3" xmlns="unknown"/> </root>""", lazy=False) self.assertEqual(set(resource.get_namespaces(root_only=False).keys()), {'default', 'tns', 'tns0'}) resource = XMLResource('<root/>') with self.assertRaises(ValueError) as ctx: resource.get_namespaces(namespaces={'xml': "http://example.com/ne"}) self.assertIn("reserved prefix (xml)", str(ctx.exception)) def test_xml_resource_get_locations(self): resource = XMLResource(self.col_xml_file) self.check_url(resource.url, normalize_url(self.col_xml_file)) locations = resource.get_locations([('ns', 'other.xsd')]) self.assertEqual(len(locations), 2) self.check_url(locations[0][1], os.path.join(self.col_dir, 'other.xsd')) self.check_url(locations[1][1], normalize_url(self.col_xsd_file)) source = StringIO('<a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' ' xsi:schemaLocation="http://example.com/ns1 /loc1"><b1>' ' <c1 xsi:schemaLocation="http://example.com/ns2 /loc2"/>' ' <c2 xmlns:tns2="http://example.com/ns2" x="2"/>' '</b1></a>') resource = XMLResource(source) locations = resource.get_locations() self.assertEqual(len(locations), 2) self.assertEqual(locations[0][0], 'http://example.com/ns1') self.assertRegex(locations[0][1], f'file://{DRIVE_REGEX}/loc1') self.assertEqual(locations[1][0], 'http://example.com/ns2') self.assertRegex(locations[1][1], f'file://{DRIVE_REGEX}/loc2') locations = resource.get_locations(root_only=True) self.assertEqual(len(locations), 1) self.assertEqual(locations[0][0], 'http://example.com/ns1') self.assertRegex(locations[0][1], f'file://{DRIVE_REGEX}/loc1') @unittest.skipIf(SKIP_REMOTE_TESTS or platform.system() == 'Windows', "Remote networks are not accessible or avoid SSL " "verification error on Windows.") def test_remote_resource_loading(self): url = "https://raw.githubusercontent.com/brunato/xmlschema/master/" \ "tests/test_cases/examples/collection/collection.xsd" with urlopen(url) as rh: col_xsd_resource = XMLResource(rh) self.assertEqual(col_xsd_resource.url, url) self.assertIsNone(col_xsd_resource.filepath) self.assertEqual(col_xsd_resource.namespace, XSD_NAMESPACE) self.assertIsNone(col_xsd_resource.seek(0)) col_xsd_resource.load() col_schema = XMLSchema(col_xsd_resource.get_text()) self.assertTrue(isinstance(col_schema, XMLSchema)) vh_schema = XMLSchema("https://raw.githubusercontent.com/brunato/xmlschema/master/" "tests/test_cases/examples/vehicles/vehicles.xsd") self.assertTrue(isinstance(vh_schema, XMLSchema)) self.assertTrue(vh_schema.source.is_remote()) def test_schema_defuse(self): vh_schema = XMLSchema(self.vh_xsd_file, defuse='always') self.assertIsInstance(vh_schema.root, etree_element) for schema in vh_schema.maps.iter_schemas(): self.assertIsInstance(schema.root, etree_element) def test_schema_resource_access(self): vh_schema = XMLSchema(self.vh_xsd_file, allow='sandbox') self.assertTrue(isinstance(vh_schema, XMLSchema)) xsd_source = """ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vh="http://example.com/vehicles"> <xs:import namespace="http://example.com/vehicles" schemaLocation="{}"/> </xs:schema>""".format(self.vh_xsd_file) schema = XMLSchema(xsd_source, allow='all') self.assertTrue(isinstance(schema, XMLSchema)) self.assertIn("http://example.com/vehicles", schema.maps.namespaces) self.assertEqual(len(schema.maps.namespaces["http://example.com/vehicles"]), 4) with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter("always") XMLSchema(xsd_source, allow='remote') self.assertEqual(len(ctx), 1, "Expected one import warning") self.assertIn("block access to local resource", str(ctx[0].message)) schema = XMLSchema(xsd_source, allow='local') self.assertTrue(isinstance(schema, XMLSchema)) self.assertIn("http://example.com/vehicles", schema.maps.namespaces) self.assertEqual(len(schema.maps.namespaces["http://example.com/vehicles"]), 4) with self.assertRaises(XMLResourceError) as ctx: XMLSchema(xsd_source, allow='sandbox') self.assertIn("block access to files out of sandbox", str(ctx.exception)) schema = XMLSchema( xsd_source, base_url=os.path.dirname(self.vh_xsd_file), allow='all' ) self.assertTrue(isinstance(schema, XMLSchema)) self.assertIn("http://example.com/vehicles", schema.maps.namespaces) self.assertEqual(len(schema.maps.namespaces["http://example.com/vehicles"]), 4) with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter("always") XMLSchema(xsd_source, base_url='/improbable', allow='sandbox') self.assertEqual(len(ctx), 1, "Expected one import warning") self.assertIn("block access to out of sandbox", str(ctx[0].message)) def test_fid_with_name_attr(self): """XMLResource gets correct data when passed a file like object with a name attribute that isn't on disk. These file descriptors appear when working with the contents from a zip using the zipfile module and with Django files in some instances. """ class FileProxy(object): def __init__(self, fid, fake_name): self._fid = fid self.name = fake_name def __getattr__(self, attr): try: return self.__dict__[attr] except (KeyError, AttributeError): return getattr(self.__dict__["_fid"], attr) with open(self.vh_xml_file) as xml_file: resource = XMLResource(FileProxy(xml_file, fake_name="not__on____disk.xml")) self.assertIsNone(resource.url) self.assertEqual(set(resource.get_namespaces().keys()), {'vh', 'xsi'}) self.assertFalse(xml_file.closed) def test_lazy_selector(self): selector = LazySelector('./*') self.assertEqual(repr(selector), "LazySelector(path='./*')") with self.assertRaises(SyntaxError): LazySelector('self::*') root = ElementTree.XML('<a><b1 c="10"/><b2/></a>') self.assertListEqual(selector.select(root), root[:]) self.assertListEqual(list(selector.iter_select(root)), root[:]) selector = LazySelector('./b1/@c') with self.assertRaises(XMLResourceError) as ctx: selector.select(root) self.assertEqual("XPath expressions on lazy resources can " "select only elements", str(ctx.exception)) with self.assertRaises(XMLResourceError) as ctx: list(selector.iter_select(root)) self.assertEqual("XPath expressions on lazy resources can " "select only elements", str(ctx.exception)) def test_parent_map(self): root = ElementTree.XML('<a><b1><c1/><c2/></b1><b2/></a>') resource = XMLResource(root) self.assertIsNone(resource.parent_map[root]) self.assertIs(resource.parent_map[root[0]], root) self.assertIs(resource.parent_map[root[1]], root) self.assertIs(resource.parent_map[root[0][0]], root[0]) self.assertIs(resource.parent_map[root[0][1]], root[0]) resource = XMLResource(StringIO('<a><b1><c1/><c2/></b1><b2/></a>'), lazy=True) with self.assertRaises(XMLResourceError) as ctx: _ = resource.parent_map self.assertEqual("cannot create the parent map of a lazy resource", str(ctx.exception)) def test_get_nsmap(self): source = '<a xmlns="uri1"><b1 xmlns:x="uri2"><c1/><c2/></b1><b2 xmlns="uri3"/></a>' alien_elem = ElementTree.XML('<a/>') root = ElementTree.XML(source) resource = XMLResource(root) self.assertListEqual(resource.get_nsmap(root), []) self.assertListEqual(resource.get_nsmap(root[1]), []) self.assertListEqual(resource.get_nsmap(alien_elem), []) if lxml_etree is not None: root = lxml_etree.XML(source) resource = XMLResource(root) self.assertListEqual(resource.get_nsmap(root), [('', 'uri1')]) self.assertListEqual(resource.get_nsmap(root[0]), [('x', 'uri2'), ('', 'uri1')]) self.assertListEqual(resource.get_nsmap(root[1]), [('', 'uri3')]) self.assertListEqual(resource.get_nsmap(alien_elem), []) resource = XMLResource(source) root = resource.root self.assertListEqual(resource.get_nsmap(root), [('', 'uri1')]) self.assertListEqual(resource.get_nsmap(root[0]), [('', 'uri1'), ('x', 'uri2')]) self.assertListEqual(resource.get_nsmap(root[1]), [('', 'uri1'), ('', 'uri3')]) self.assertListEqual(resource.get_nsmap(alien_elem), []) resource = XMLResource(StringIO(source), lazy=True) root = resource.root self.assertTrue(resource.is_lazy()) self.assertListEqual(resource.get_nsmap(root), [('', 'uri1')]) self.assertListEqual(resource.get_nsmap(root[0]), []) self.assertListEqual(resource.get_nsmap(root[1]), []) self.assertListEqual(resource.get_nsmap(alien_elem), []) def test_xml_subresource(self): resource = XMLResource(self.vh_xml_file, lazy=True) with self.assertRaises(XMLResourceError) as ctx: resource.subresource(resource.root) self.assertEqual("cannot create a subresource from a lazy resource", str(ctx.exception)) resource = XMLResource(self.vh_xml_file) root = resource.root subresource = resource.subresource(root[0]) self.assertIs(subresource.root, resource.root[0]) with self.assertRaises(XMLResourceError) as ctx: resource.subresource(None) self.assertEqual("None is not an element or the XML resource tree", str(ctx.exception)) if lxml_etree is not None: resource = XMLResource(lxml_etree.parse(self.vh_xml_file).getroot()) root = resource.root subresource = resource.subresource(root[0]) self.assertIs(subresource.root, resource.root[0]) xml_text = '<a><b1 xmlns:x="tns0"><c1 xmlns:y="tns1"/><c2/></b1><b2/></a>' resource = XMLResource(xml_text) root = resource.root subresource = resource.subresource(root[0]) self.assertIs(subresource.root, resource.root[0]) def test_loading_from_unrelated_dirs__issue_237(self): relative_path = str(pathlib.Path(__file__).parent.joinpath( 'test_cases/issues/issue_237/dir1/issue_237.xsd' )) schema = XMLSchema(relative_path) self.assertEqual(schema.maps.namespaces[''][1].name, 'issue_237a.xsd') self.assertEqual(schema.maps.namespaces[''][2].name, 'issue_237b.xsd') if __name__ == '__main__': header_template = "Test xmlschema's XML resources with Python {} on platform {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_schemas.py��������������������������������������������������������������0000664�0000000�0000000�00000003371�14211403446�0017753�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning the parsing and the building of XSD schemas""" import os from xmlschema.testing import get_test_program_args_parser, \ factory_tests, make_schema_test_class DEFAULT_TESTFILES = os.path.join(os.path.dirname(__file__), 'test_cases/testfiles') if __name__ == '__main__': import unittest import platform args = get_test_program_args_parser(DEFAULT_TESTFILES).parse_args() schema_tests = factory_tests( test_class_builder=make_schema_test_class, testfiles=args.testfiles, suffix='xsd', check_with_lxml=args.lxml, codegen=args.codegen, verbosity=args.verbosity, ) globals().update(schema_tests) argv = [__file__] if args.tb_locals: argv.append('--local') for pattern in args.patterns: argv.append('-k') argv.append(pattern) header_template = "Schema building tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main(argv=argv, verbosity=args.verbosity, failfast=args.failfast, catchbreak=args.catchbreak, buffer=args.buffer) else: # Creates schema tests from XSD files globals().update(factory_tests( test_class_builder=make_schema_test_class, suffix='xsd', testfiles=DEFAULT_TESTFILES )) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_typing.py���������������������������������������������������������������0000664�0000000�0000000�00000003450�14211403446�0017640�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests about static typing of xmlschema objects.""" import unittest import subprocess import re from pathlib import Path try: import mypy except ImportError: mypy = None @unittest.skipIf(mypy is None, "mypy is not installed") class TestTyping(unittest.TestCase): @classmethod def setUpClass(cls): cls.cases_dir = Path(__file__).parent.joinpath('test_cases/mypy') cls.config_file = Path(__file__).parent.parent.joinpath('mypy.ini') cls.error_pattern = re.compile(r'Found \d+ error', re.IGNORECASE) def check_mypy_output(self, testfile, *options): cmd = ['mypy', '--config-file', str(self.config_file), testfile] if options: cmd.extend(str(opt) for opt in options) process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.assertEqual(process.stderr, b'') output = process.stdout.decode('utf-8').strip() output_lines = output.split('\n') self.assertGreater(len(output_lines), 0, msg=output) self.assertNotRegex(output_lines[-1], self.error_pattern, msg=output) return output_lines def test_simple_types(self): case_path = self.cases_dir.joinpath('simple_types.py') output_lines = self.check_mypy_output(case_path, '--strict', '--no-warn-unused-ignores') self.assertTrue(output_lines[0].startswith('Success:'), msg='\n'.join(output_lines)) if __name__ == '__main__': unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_validation.py�����������������������������������������������������������0000664�0000000�0000000�00000003416�14211403446�0020462�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning the validation/decoding/encoding of XML files""" import os from xmlschema.testing import get_test_program_args_parser, \ factory_tests, make_validation_test_class DEFAULT_TESTFILES = os.path.join(os.path.dirname(__file__), 'test_cases/testfiles') if __name__ == '__main__': import unittest import platform args = get_test_program_args_parser(DEFAULT_TESTFILES).parse_args() validation_tests = factory_tests( test_class_builder=make_validation_test_class, testfiles=args.testfiles, suffix='xml', check_with_lxml=args.lxml, codegen=args.codegen, verbosity=args.verbosity, ) globals().update(validation_tests) argv = [__file__] if args.tb_locals: argv.append('--local') for pattern in args.patterns: argv.append('-k') argv.append(pattern) header_template = "XML validation tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main(argv=argv, verbosity=args.verbosity, failfast=args.failfast, catchbreak=args.catchbreak, buffer=args.buffer) else: # Creates schema tests from XSD files globals().update(factory_tests( test_class_builder=make_validation_test_class, suffix='xml', testfiles=DEFAULT_TESTFILES )) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_w3c_suite.py������������������������������������������������������������0000664�0000000�0000000�00000065273�14211403446�0020246�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This script runs tests concerning the W3C XML Schema 1.1 test suite. """ import unittest import argparse import os.path import warnings try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema import validate, XMLSchema10, XMLSchema11, XMLSchemaException from xmlschema.etree import ElementTree TEST_SUITE_NAMESPACE = "http://www.w3.org/XML/2004/xml-schema-test-suite/" XLINK_NAMESPACE = "http://www.w3.org/1999/xlink" XSD_VERSION_VALUES = {'1.0 1.1', '1.0', '1.1'} ADMITTED_VALIDITY = {'valid', 'invalid', 'indeterminate'} #### # Tests that are incompatible with XSD meta-schema validation or that are postponed SKIPPED_TESTS = { ## # Skip for typos in test data '../msData/regex/reZ003v.xml', # 13589 '../ibmData/instance_invalid/S3_10_6/s3_10_6ii01.xsd', # 14911 '../ibmData/instance_invalid/S3_10_6/s3_10_6ii02.xsd', # 14912 '../ibmData/instance_invalid/S3_10_6/s3_10_6ii04.xsd', # 14914 '../ibmData/instance_invalid/S3_10_1/s3_10_1ii08.xsd', # 15360 '../ibmData/instance_invalid/S3_10_1/s3_10_1ii09.xsd', # 15361 ## # Invalid schemas marked as valid '../msData/additional/addB194.xsd', # invalid xml:lang='enu' is a typo? '../msData/particles/particlesZ001.xsd', # Invalid XSD 1.0 schema (valid with XSD 1.1) '../msData/simpleType/stE110.xsd', # Circular xs:union declaration '../saxonData/Missing/missing001.xsd', # missing type (this may be valid in 'lax' mode?) '../saxonData/Missing/missing002.xsd', # missing substitution group '../saxonData/Missing/missing003.xsd', # missing type and substitution group '../saxonData/Missing/missing006.xsd', # missing list item type '../msData/annotations/annotF001.xsd', # xml.xsd allows xml:lang="" for un-declarations ## # XSD 1.0 limited URI (see RFC 2396 + RFC 2732) '../msData/datatypes/Facets/anyURI/anyURI_a001.xsd', '../msData/datatypes/Facets/anyURI/anyURI_a003.xsd', '../msData/datatypes/Facets/anyURI/anyURI_b004.xsd', '../msData/datatypes/Facets/anyURI/anyURI_b006.xsd', ## # Uncertain cases (disputed tests) '../msData/group/groupH021.xsd', # 8679: Unclear invalidity stated for XSD 1.0 ... # # Two uncertain equivalent cases related with element # substitution and its equivalence with a choice group. # Xerces says these are both invalid with XSD 1.0 and valid with XSD 1.1. # # http://www.w3.org/Bugs/Public/show_bug.cgi?id=4146 # http://www.w3.org/Bugs/Public/show_bug.cgi?id=4147 # '../msData/element/elemZ026.xsd', # 8541: bug id=4147 '../msData/particles/particlesV020.xsd', # 10942: bug id=4147 ## # 7295: Inapplicable test on URI (the first resource is not reachable anymore) # https://www.w3.org/Bugs/Public/show_bug.cgi?id=4126 '../msData/datatypes/Facets/anyURI/anyURI_a004.xml', ## # Signed ad invalid, but valid because depends by implementation choices or platform. # https://www.w3.org/Bugs/Public/show_bug.cgi?id=4133 '../msData/schema/schG3.xml', '../msData/schema/schG6_a.xsd', # Valid because the ns import is done once, validation fails. '../msData/schema/schG11_a.xsd', # Valid because the ns import is done once, validation fails. '../msData/schema/schG12.xml', '../msData/element/elemZ031.xsd', # Valid because Python has arbitrary large integers ## # Invalid XML tests '../sunData/combined/xsd005/xsd005.n05.xml', # 3984: Invalid if lxml is used (xsi:type and duplicate prefix) '../msData/additional/test93490_4.xml', # 4795: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4078 '../msData/additional/test93490_8.xml', # 4799: Idem '../msData/datatypes/gMonth002.xml', # 8017: gMonth bogus: conflicts with other invalid schema tests '../msData/datatypes/gMonth004.xml', # 8019: (http://www.w3.org/Bugs/Public/show_bug.cgi?id=6901) '../wgData/sg/e1.xml', # 14896: wrong href for valid instanceTest name="e1bis.xml" ## # Unicode version related '../msData/regex/reJ11.xml', '../msData/regex/reJ13.xml', '../msData/regex/reJ19.xml', '../msData/regex/reJ21.xml', '../msData/regex/reJ23.xml', '../msData/regex/reJ25.xml', '../msData/regex/reJ29.xml', '../msData/regex/reJ31.xml', '../msData/regex/reJ33.xml', '../msData/regex/reJ35.xml', '../msData/regex/reJ61.xml', '../msData/regex/reJ69.xml', '../msData/regex/reJ75.xml', '../msData/regex/reJ77.xml', '../msData/regex/reL98.xml', '../msData/regex/reL99.xml', '../msData/regex/reM98.xml', '../msData/regex/reN99.xml', '../msData/regex/reS21.xml', '../msData/regex/reS42.xml', '../msData/regex/reT63.xml', '../msData/regex/reT84.xml', # http://www.w3.org/Bugs/Public/show_bug.cgi?id=4113 '../msData/regex/reV16.xml', '../msData/regex/reV17.xml', '../msData/regex/reV18.xml', '../msData/regex/reV19.xml', '../msData/regex/reV20.xml', '../msData/regex/reV21.xml', '../msData/regex/reV22.xml', '../msData/regex/reV23.xml', '../msData/regex/reV24.xml', '../msData/regex/reV33.xml', '../msData/regex/reV34.xml', '../msData/regex/reV35.xml', '../msData/regex/reV36.xml', '../msData/regex/reV37.xml', '../msData/regex/reV38.xml', '../msData/regex/reV39.xml', '../msData/regex/reV40.xml', '../msData/regex/reV41.xml', '../msData/regex/reV42.xml', '../msData/regex/reV43.xml', # Tests with \W pattern and characters belonging to the M category ## # Skip for missing XML version 1.1 implementation '../saxonData/XmlVersions/xv001.v01.xml', # 14850 '../saxonData/XmlVersions/xv003.v01.xml', # 14852 '../saxonData/XmlVersions/xv004.xsd', # 14853 non-BMP chars allowed in names in XML 1.1+ '../saxonData/XmlVersions/xv005.v01.xml', # 14854 '../saxonData/XmlVersions/xv006.v01.xml', # 14855 invalid character  (valid in XML 1.1) '../saxonData/XmlVersions/xv006.n02.xml', # 14855 invalid character 𐀀 (valid in XML 1.1) '../saxonData/XmlVersions/xv007.v01.xml', # 14856 '../saxonData/XmlVersions/xv008.v01.xml', # 14857 '../saxonData/XmlVersions/xv008.n01.xml', '../saxonData/XmlVersions/xv009.v02.xml', # 14858 '../saxonData/XmlVersions/xv009.n02.xml', '../saxonData/XmlVersions/xv009.n03.xml', '../saxonData/XmlVersions/xv100.i.xml', # 14859 '../saxonData/XmlVersions/xv100.c.xml', # 14860 ## # Skip for TODO '../msData/additional/test93490_2.xml', # 4793 '../msData/additional/test93490_5.xml', # 4796 '../msData/additional/test93490_7.xml', # 4798 '../msData/additional/test93490_10.xml', # 4801 '../msData/additional/test93490_12.xml', # 4803 '../msData/additional/addB191.xml', # 4824 # Dynamic schema load cases } XSD10_SKIPPED_TESTS = { # Invalid schemas marked as valid '../msData/simpleType/stE072.xsd', # 13868: a union derived from ID with a fixed value '../msData/simpleType/stE072.xml', } XSD11_SKIPPED_TESTS = { # Valid schemas marked ad invalid '../msData/regex/reK86.xsd', # \P{Is} is valid in regex for XSD 1.1 '../msData/regex/reK87.xsd', # \P{Is} is valid in regex for XSD 1.1 '../msData/particles/particlesZ033_g.xsd', # valid in XSD 1.1 (invalid for engine limitation) '../saxonData/CTA/cta0043.xsd', # Only a warning for type table difference on restriction # TODO: Parse ENTITY declarations in DOCTYPE before enforce checking '../saxonData/Id/id017.n01.xml', # 14571-14575 '../saxonData/Id/id018.n01.xml', '../saxonData/Id/id018.n02.xml', '../saxonData/Id/id019.n01.xml', '../saxonData/Id/id019.n02.xml', '../saxonData/Id/id020.n01.xml', '../saxonData/Id/id020.n02.xml', '../saxonData/Id/id021.n01.xml', '../saxonData/Id/id021.n02.xml', } DO_NOT_USE_META_SCHEMA = { '../msData/additional/test264908_1.xsd', } DO_NOT_USE_FALLBACK_LOCATIONS = { '../msData/wildcards/wildZ001.xml', } # Total files counters total_xsd_files = 0 total_xml_files = 0 def fetch_xsd_test_suite(): parent = os.path.dirname xmlschema_test_dir = parent(os.path.abspath(__file__)) xmlschema_base_dir = parent(xmlschema_test_dir) suite_file = os.path.join(parent(xmlschema_base_dir), 'xsdtests/suite.xml') if os.path.isfile(suite_file): return suite_file else: raise FileNotFoundError("can't find the XSD suite index file suite.xml ...") def skip_message(source_href, group_num, version='each'): if source_href.endswith('.xsd'): msg = "Skip test number {} with schema {!r} for {} version ..." else: msg = "Skip test number {} with file {!r} for {} version ..." print(msg.format(group_num, source_href, version)) def create_w3c_test_group_case(args, filename, group_elem, group_num, xsd_version='1.0'): """ Creates a test class for a W3C test group. :param args: parsed command line arguments. :type args: argparse.Namespace. :param filename: the filename of the testSet that owns the testGroup. :param group_elem: the Element instance of the test group. :param group_num: a positive integer to distinguish and order test groups. :param xsd_version: if '1.1' uses XSD 1.1 validator class, otherwise uses the XSD 1.0 validator. """ def get_test_conf(elem): schema_test = elem.tag.endswith('schemaTest') if schema_test: tag = '{%s}schemaDocument' % TEST_SUITE_NAMESPACE else: tag = '{%s}instanceDocument' % TEST_SUITE_NAMESPACE try: source_href = elem.find(tag).get('{%s}href' % XLINK_NAMESPACE) except AttributeError: return else: if not schema_test and source_href.endswith('.testSet'): return if source_href in SKIPPED_TESTS: if args.numbers: skip_message(source_href, group_num) return # Normalize and check file path source_path = os.path.normpath(os.path.join(os.path.dirname(filename), source_href)) if not os.path.isfile(source_path): print("ERROR: file %r not found!" % source_path) return test_conf = {} for version in xsd_version.split(): if 'version' in elem.attrib and version not in elem.attrib['version']: continue elif version not in args.version: continue elif source_href in XSD10_SKIPPED_TESTS and version == '1.0' or \ source_href in XSD11_SKIPPED_TESTS and version == '1.1': if args.numbers: skip_message(source_href, group_num, version) continue for e in elem.findall('{%s}expected' % TEST_SUITE_NAMESPACE): if 'version' not in e.attrib: test_conf[version] = e.attrib['validity'] elif e.attrib['version'] == version or \ e.attrib['version'] == 'full-xpath-in-CTA': test_conf[version] = e.attrib['validity'] break if version not in test_conf: msg = "ERROR: Missing expected validity for XSD version %s in %r of test group %r" print(msg % (version, elem, name)) return elif test_conf[version] not in ADMITTED_VALIDITY: msg = "ERROR: Wrong validity=%r attribute for XSD version %s in %r test group %r" print(msg % (test_conf[version], version, elem, name)) return elif test_conf[version] not in args.expected: test_conf.pop(version) elif test_conf[version] == 'indeterminate': if args.verbose: print("WARNING: Skip indeterminate test group %r" % name) test_conf.pop(version) if test_conf: test_conf['source'] = source_path if schema_test: if not source_path.endswith('.xml'): test_conf['sources'] = [ os.path.normpath( os.path.join(os.path.dirname(filename), schema_href.get('{%s}href' % XLINK_NAMESPACE)) ) for schema_href in elem.findall(tag) ] if source_href in DO_NOT_USE_META_SCHEMA: nonlocal use_meta use_meta = False if source_href in DO_NOT_USE_FALLBACK_LOCATIONS: nonlocal use_fallback use_fallback = False return test_conf if group_num == 1: return # Skip introspection tests that have several failures due to schema mismatch. elif args.numbers and group_num not in args.numbers: return name = group_elem.attrib['name'] group_tests = [] global total_xsd_files global total_xml_files use_meta = True use_fallback = True # Get schema/instance path for k, child in enumerate(group_elem.iterfind('{%s}schemaTest' % TEST_SUITE_NAMESPACE)): if k: print("ERROR: multiple schemaTest definition in group %r" % name) return config = get_test_conf(child) if not config: return group_tests.append(config) total_xsd_files += 1 if args.xml: for child in group_elem.iterfind('{%s}instanceTest' % TEST_SUITE_NAMESPACE): if 'version' in child.attrib and child.attrib['version'] not in args.version: continue config = get_test_conf(child) if config: group_tests.append(config) total_xml_files += 1 if not group_tests: if len(args.expected) > 1 and args.xml: print("ERROR: Missing both schemaTest and instanceTest in test group %r" % name) return class TestGroupCase(unittest.TestCase): @unittest.skipIf(group_tests[0]['source'].endswith('.xml'), 'No schema test') def test_xsd_schema(self): for item in filter(lambda x: x['source'].endswith('.xsd'), group_tests): source = item['source'] rel_path = os.path.relpath(source) for version, expected in \ sorted(filter(lambda x: not x[0].startswith('source'), item.items())): if args.lxml and version == '1.0': if expected == 'invalid': with self.assertRaises(lxml_etree.XMLSchemaParseError): schema_tree = lxml_etree.parse(source) lxml_etree.XMLSchema(schema_tree) else: schema_tree = lxml_etree.parse(source) lxml_etree.XMLSchema(schema_tree) continue schema_class = XMLSchema11 if version == '1.1' else XMLSchema10 if expected == 'invalid': message = "schema %s should be invalid with XSD %s" % (rel_path, version) with self.assertRaises(XMLSchemaException, msg=message): with warnings.catch_warnings(): warnings.simplefilter('ignore') if len(item['sources']) <= 1: schema_class(source, use_meta=use_meta, use_fallback=use_fallback) else: schema = schema_class(source, use_meta=use_meta, use_fallback=use_fallback, build=False) for other in item['sources'][1:]: schema_class(other, global_maps=schema.maps, use_fallback=use_fallback, build=False) schema.build() else: try: with warnings.catch_warnings(): warnings.simplefilter('ignore') if len(item['sources']) <= 1: schema = schema_class(source, use_meta=use_meta, use_fallback=use_fallback) else: schema = schema_class(source, use_meta=use_meta, use_fallback=use_fallback, build=False) for other in item['sources'][1:]: schema_class(other, global_maps=schema.maps, use_fallback=use_fallback, build=False) schema.build() except XMLSchemaException as err: schema = None message = "schema %s should be valid with XSD %s, but an error " \ "is raised:\n\n%s" % (rel_path, version, str(err)) else: message = None self.assertIsInstance(schema, schema_class, msg=message) @unittest.skipIf( group_tests[0]['source'].endswith('.xsd') and len(group_tests) == 1, 'No instance tests' ) def test_xml_instances(self): if group_tests[0]['source'].endswith('.xsd'): schema = group_tests[0]['source'] schemas = group_tests[0]['sources'] else: schema = None schemas = [] for item in filter(lambda x: not x['source'].endswith('.xsd'), group_tests): source = item['source'] rel_path = os.path.relpath(source) for version, expected in sorted(filter(lambda x: x[0] != 'source', item.items())): schema_class = XMLSchema11 if version == '1.1' else XMLSchema10 if expected == 'invalid': message = "instance %s should be invalid with XSD %s" % (rel_path, version) with self.assertRaises((XMLSchemaException, ElementTree.ParseError), msg=message): with warnings.catch_warnings(): warnings.simplefilter('ignore') if not schemas: validate(source, schema=schema, cls=schema_class) else: xs = schema_class(schemas[0], use_meta=use_meta, use_fallback=use_fallback, build=False) for other in schemas[1:]: schema_class(other, global_maps=xs.maps, use_fallback=use_fallback, build=False) xs.build() xs.validate(source) else: try: with warnings.catch_warnings(): warnings.simplefilter('ignore') if len(schemas) <= 1 and use_meta and use_fallback: validate(source, schema=schema, cls=schema_class) else: xs = schema_class(schemas[0], use_meta=use_meta, use_fallback=use_fallback, build=False) for other in schemas[1:]: schema_class(other, global_maps=xs.maps, build=False) xs.build() xs.validate(source) except (XMLSchemaException, ElementTree.ParseError) as err: error = "instance %s should be valid with XSD %s, but an error " \ "is raised:\n\n%s" % (rel_path, version, str(err)) else: error = None self.assertIsNone(error) if not any(g['source'].endswith('.xsd') for g in group_tests): del TestGroupCase.test_xsd_schema if not any(g['source'].endswith('.xml') for g in group_tests): del TestGroupCase.test_xml_instances TestGroupCase.__name__ = TestGroupCase.__qualname__ = str( 'TestGroupCase{0:05}_{1}'.format(group_num, name.replace('-', '_')) ) return TestGroupCase def w3c_tests_factory(argv=None): import sys if argv is None: argv = sys.argv[1:] def xsd_versions(value): if value not in ('1.0', '1.1', '1.0 1.1', '1.1 1.0'): raise argparse.ArgumentTypeError("%r is not an XSD version string" % value) return value def number_or_interval(value): try: return int(value) except ValueError: if '-' not in value: raise try: start, stop = value.split('-') return [int(start), int(stop)] except ValueError: pass raise def iter_numbers(numbers): for x in numbers: if isinstance(x, int): yield x elif isinstance(x, list) and len(x) == 2: yield from range(x[0], x[1] + 1) parser = argparse.ArgumentParser(add_help=True) parser.add_argument('-v', '--verbose', default=False, action='store_true') parser.add_argument('--version', dest='version', type=xsd_versions, default='1.0 1.1', help="Run only tests related to a specific XSD version.") parser.add_argument('--xml', default=False, action='store_true', help="Include XML validation tests.") parser.add_argument('--lxml', default=False, action='store_true', help="Use lxml's XMLSchema validator for XSD 1.0 tests.") parser.add_argument('--valid', dest='expected', default=ADMITTED_VALIDITY, const='valid', action='store_const', help="Run only expected 'valid' tests.") parser.add_argument('--invalid', dest='expected', const='invalid', action='store_const', help="Run only expected 'invalid' tests.") parser.add_argument('--unknown', dest='expected', const='indeterminate', action='store_const', help="Run only expected 'indeterminate' tests.") parser.add_argument('numbers', metavar='TEST_NUMBER', type=number_or_interval, nargs='*', help='Runs only specific tests, selected by numbers.') args = parser.parse_args(args=argv) args.numbers = [x for x in iter_numbers(args.numbers)] if lxml_etree is None and args.lxml: print("Ignore --lxml option: library lxml is not available ...") args.lxml = False quiet = __name__ == '__main__' index_path = fetch_xsd_test_suite() index_dir = os.path.dirname(index_path) suite_xml = ElementTree.parse(index_path) test_classes = {} testgroup_num = 0 if args.verbose and not quiet: print("\n>>>>> ADD TEST GROUPS FROM TESTSET FILES <<<<<\n") for testset_elem in suite_xml.iter("{%s}testSetRef" % TEST_SUITE_NAMESPACE): href_attr = testset_elem.attrib.get("{%s}href" % XLINK_NAMESPACE, '') testset_file = os.path.join(index_dir, href_attr) testset_groups = 0 testset = ElementTree.parse(testset_file) testset_version = testset.getroot().get('version', '1.0 1.1') if testset_version not in XSD_VERSION_VALUES: if not quiet: msg = "Testset file %r has an invalid version=%r, skip ..." print(msg % (href_attr, testset_version)) continue for testgroup_elem in testset.iter("{%s}testGroup" % TEST_SUITE_NAMESPACE): testgroup_num += 1 testgroup_version = testgroup_elem.get('version', testset_version) if testgroup_version == 'full-xpath-in-CTA': # skip full XPath test for the moment ... if args.verbose and not quiet: print("Skip full XPath test %r ..." % testgroup_elem.get('name')) continue elif testgroup_version not in XSD_VERSION_VALUES: if not quiet: _msg = "Test group %r has an invalid version=%r, skip ..." print(_msg % (testgroup_elem.get('name'), testgroup_version)) continue elif testgroup_version not in testset_version: if args.verbose and not quiet: _msg = "Warning: Test group %r version=%r is not included " \ "in test set version=%r" print(_msg % (testgroup_elem.get('name'), testgroup_version, testset_version)) cls = create_w3c_test_group_case( args=args, filename=testset_file, group_elem=testgroup_elem, group_num=testgroup_num, xsd_version=testgroup_version, ) if cls is not None: test_classes[cls.__name__] = cls testset_groups += 1 if args.verbose and testset_groups and not quiet: print("Added {} test groups from {}".format(testset_groups, href_attr)) if test_classes and not quiet: print("\n+++ Number of classes under test: %d +++" % len(test_classes)) if total_xml_files: print("+++ Number of XSD schemas under test: %d +++" % total_xsd_files) print("+++ Number of XML files under test: %d +++" % total_xml_files) print() if args.verbose and not quiet: print("\n>>>>> RUN TEST GROUPS <<<<<\n") return test_classes if __name__ == '__main__': import platform header_template = "W3C XSD tests for xmlschema with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) globals().update(w3c_tests_factory()) unittest.main(argv=[__name__]) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/test_wsdl.py�����������������������������������������������������������������0000664�0000000�0000000�00000124664�14211403446�0017312�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning WSDL documents. Examples from WSDL 1.1 definition document.""" import unittest import pathlib from xmlschema import XMLSchemaValidationError, XMLSchema10, XMLSchema11 from xmlschema.etree import ElementTree, ParseError from xmlschema.extras.wsdl import WsdlParseError, WsdlComponent, WsdlMessage, \ WsdlPortType, WsdlOperation, WsdlBinding, WsdlService, Wsdl11Document, \ WsdlInput, SoapHeader TEST_CASES_DIR = str(pathlib.Path(__file__).absolute().parent.joinpath('test_cases')) def casepath(relative_path): return str(pathlib.Path(TEST_CASES_DIR).joinpath(relative_path)) WSDL_DOCUMENT_EXAMPLE = """<?xml version="1.0"?> <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2001/XMLSchema"> <element name="TradePriceRequest"> <complexType> <all> <element name="tickerSymbol" type="string"/> </all> </complexType> </element> <element name="TradePrice"> <complexType> <all> <element name="price" type="float"/> </all> </complexType> </element> </schema> </types> <message name="GetLastTradePriceInput"> <part name="body" element="xsd1:TradePriceRequest"/> </message> <message name="GetLastTradePriceOutput"> <part name="body" element="xsd1:TradePrice"/> </message> <portType name="StockQuotePortType"> <operation name="GetLastTradePrice"> <input message="tns:GetLastTradePriceInput"/> <output message="tns:GetLastTradePriceOutput"/> </operation> </portType> <binding name="StockQuoteBinding" type="tns:StockQuotePortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="GetLastTradePrice"> <soap:operation soapAction="http://example.com/GetLastTradePrice"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding> <service name="StockQuoteService"> <documentation>My first service</documentation> <port name="StockQuotePort" binding="tns:StockQuoteBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions> """ WSDL_DOCUMENT_NO_SOAP = """<?xml version="1.0"?> <wsdl:definitions name="minimal" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <wsdl:message name="myMessage"> <wsdl:part name="content" type="xs:string"/> </wsdl:message> <wsdl:portType name="myPortType"> <wsdl:operation name="myOperation"> <wsdl:input message="myMessage"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="myBinding" type="myPortType"> <wsdl:operation name="myOperation"> <wsdl:input/> </wsdl:operation> </wsdl:binding> <wsdl:service name="myService"> <wsdl:port name="myPort" binding="myBinding"/> </wsdl:service> </wsdl:definitions> """ class TestWsdlDocuments(unittest.TestCase): @classmethod def setUpClass(cls): cls.vh_dir = casepath('examples/vehicles') cls.vh_xsd_file = casepath('examples/vehicles/vehicles.xsd') cls.vh_xml_file = casepath('examples/vehicles/vehicles.xml') cls.col_dir = casepath('examples/collection') cls.col_xsd_file = casepath('examples/collection/collection.xsd') cls.col_xml_file = casepath('examples/collection/collection.xml') def test_wsdl_document_init(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) self.assertEqual(wsdl_document.target_namespace, "http://example.com/stockquote.wsdl") self.assertIsInstance(wsdl_document.schema, XMLSchema10) wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, cls=XMLSchema11) self.assertIsInstance(wsdl_document.schema, XMLSchema11) self.assertIn('http://example.com/stockquote.xsd', wsdl_document.schema.maps.namespaces) self.assertIn('{http://example.com/stockquote.xsd}TradePriceRequest', wsdl_document.schema.maps.elements) self.assertIn('{http://example.com/stockquote.xsd}TradePrice', wsdl_document.schema.maps.elements) self.assertIn('{http://example.com/stockquote.wsdl}GetLastTradePriceInput', wsdl_document.maps.messages) self.assertIn('{http://example.com/stockquote.wsdl}GetLastTradePriceOutput', wsdl_document.maps.messages) for message in wsdl_document.maps.messages.values(): self.assertIsInstance(message, WsdlMessage) self.assertIn('{http://example.com/stockquote.wsdl}StockQuotePortType', wsdl_document.maps.port_types) for port_type in wsdl_document.maps.port_types.values(): self.assertIsInstance(port_type, WsdlPortType) for operation in port_type.operations.values(): self.assertIsInstance(operation, WsdlOperation) self.assertIn('{http://example.com/stockquote.wsdl}StockQuoteBinding', wsdl_document.maps.bindings) for bindings in wsdl_document.maps.bindings.values(): self.assertIsInstance(bindings, WsdlBinding) for operation in bindings.operations.values(): self.assertIsInstance(operation, WsdlOperation) self.assertIn('{http://example.com/stockquote.wsdl}StockQuoteService', wsdl_document.maps.services) for service in wsdl_document.maps.services.values(): self.assertIsInstance(service, WsdlService) wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, locations=[('x', 'y'), ('x', 'z')]) self.assertEqual(wsdl_document.locations, {'x': ['y', 'z']}) def test_schema_class(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) self.assertIsInstance(wsdl_document.schema, XMLSchema10) wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, cls=XMLSchema11) self.assertIsInstance(wsdl_document.schema, XMLSchema11) def test_validation_mode(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) self.assertEqual(wsdl_document.validation, 'strict') with self.assertRaises(WsdlParseError) as ctx: wsdl_document.parse_error('wrong syntax') self.assertIn("wrong syntax", str(ctx.exception)) wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, validation='lax') self.assertEqual(wsdl_document.validation, 'lax') wsdl_document.parse_error('wrong syntax') self.assertEqual(len(wsdl_document.errors), 1) self.assertIn("wrong syntax", str(wsdl_document.errors[0])) wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, validation='skip') self.assertEqual(wsdl_document.validation, 'skip') wsdl_document.parse_error('wrong syntax') self.assertEqual(len(wsdl_document.errors), 0) with self.assertRaises(ValueError) as ctx: Wsdl11Document(WSDL_DOCUMENT_EXAMPLE, validation='invalid') self.assertEqual("'invalid': not a validation mode", str(ctx.exception)) def test_example3(self): original_example3_file = casepath('features/wsdl/wsdl11_example3.wsdl') with self.assertRaises(XMLSchemaValidationError): Wsdl11Document(original_example3_file) wsdl_document = Wsdl11Document(original_example3_file, validation='lax') self.assertEqual(len(wsdl_document.errors), 1) example3_file = casepath('features/wsdl/wsdl11_example3_valid.wsdl') wsdl_document = Wsdl11Document(example3_file) message_name = '{http://example.com/stockquote.wsdl}SubscribeToQuotes' self.assertListEqual(list(wsdl_document.messages), [message_name]) message = wsdl_document.messages[message_name] self.assertListEqual(list(message.parts), ['body', 'subscribeheader']) port_type_name = '{http://example.com/stockquote.wsdl}StockQuotePortType' self.assertListEqual(list(wsdl_document.port_types), [port_type_name]) port_type = wsdl_document.port_types[port_type_name] self.assertEqual(list(port_type.operations), [('SubscribeToQuotes', None, None)]) operation = port_type.operations[('SubscribeToQuotes', None, None)] self.assertIsNone(operation.soap_operation) self.assertEqual(operation.input.soap_body.use, 'literal') self.assertEqual(len(operation.input.soap_headers), 1) self.assertIs(operation.input.soap_headers[0].message, message) self.assertIs(operation.input.soap_headers[0].part, message.parts['subscribeheader']) binding_name = '{http://example.com/stockquote.wsdl}StockQuoteSoap' self.assertListEqual(list(wsdl_document.bindings), [binding_name]) binding = wsdl_document.bindings[binding_name] self.assertIs(binding.port_type, port_type) self.assertEqual(binding.soap_transport, "http://example.com/smtp") self.assertEqual(binding.soap_style, "document") service_name = '{http://example.com/stockquote.wsdl}StockQuoteService' self.assertListEqual(list(wsdl_document.services), [service_name]) self.assertEqual(list(wsdl_document.services[service_name].ports), ['StockQuotePort']) port = wsdl_document.services[service_name].ports['StockQuotePort'] self.assertEqual(port.soap_location, 'mailto:subscribe@example.com') def test_example4(self): original_example4_file = casepath('features/wsdl/wsdl11_example4.wsdl') with self.assertRaises(XMLSchemaValidationError): Wsdl11Document(original_example4_file) example_4_file = casepath('features/wsdl/wsdl11_example4_valid.wsdl') wsdl_document = Wsdl11Document(example_4_file) message1_name = '{http://example.com/stockquote.wsdl}GetTradePriceInput' message2_name = '{http://example.com/stockquote.wsdl}GetTradePriceOutput' self.assertListEqual(list(wsdl_document.messages), [message1_name, message2_name]) message1 = wsdl_document.messages[message1_name] message2 = wsdl_document.messages[message2_name] self.assertListEqual(list(message1.parts), ['tickerSymbol', 'time']) self.assertListEqual(list(message2.parts), ['result']) port_type_name = '{http://example.com/stockquote.wsdl}StockQuotePortType' self.assertListEqual(list(wsdl_document.port_types), [port_type_name]) port_type = wsdl_document.port_types[port_type_name] self.assertEqual(list(port_type.operations), [('GetTradePrice', None, None)]) operation = port_type.operations[('GetTradePrice', None, None)] self.assertIsNotNone(operation.soap_operation) self.assertEqual(operation.soap_action, 'http://example.com/GetTradePrice') self.assertEqual(operation.soap_style, 'document') self.assertIs(operation.input.message, message1) self.assertIs(operation.output.message, message2) self.assertEqual(operation.input.soap_body.use, 'encoded') self.assertEqual(operation.input.soap_body.namespace, 'http://example.com/stockquote') self.assertEqual(operation.input.soap_body.encoding_style, 'http://schemas.xmlsoap.org/soap/encoding/') self.assertEqual(len(operation.input.soap_headers), 0) self.assertEqual(operation.output.soap_body.use, 'encoded') self.assertEqual(operation.output.soap_body.namespace, 'http://example.com/stockquote') self.assertEqual(operation.output.soap_body.encoding_style, 'http://schemas.xmlsoap.org/soap/encoding/') self.assertEqual(len(operation.output.soap_headers), 0) binding_name = '{http://example.com/stockquote.wsdl}StockQuoteBinding' self.assertListEqual(list(wsdl_document.bindings), [binding_name]) binding = wsdl_document.bindings[binding_name] self.assertIs(binding.port_type, port_type) self.assertEqual(binding.soap_transport, "http://schemas.xmlsoap.org/soap/http") self.assertEqual(binding.soap_style, "rpc") service_name = '{http://example.com/stockquote.wsdl}StockQuoteService' self.assertListEqual(list(wsdl_document.services), [service_name]) self.assertEqual(list(wsdl_document.services[service_name].ports), ['StockQuotePort']) port = wsdl_document.services[service_name].ports['StockQuotePort'] self.assertEqual(port.soap_location, 'http://example.com/stockquote') def test_example5(self): original_example5_file = casepath('features/wsdl/wsdl11_example5.wsdl') with self.assertRaises(ParseError): Wsdl11Document(original_example5_file) example5_file = casepath('features/wsdl/wsdl11_example5_valid.wsdl') wsdl_document = Wsdl11Document(example5_file) message1_name = '{http://example.com/stockquote.wsdl}GetTradePricesInput' message2_name = '{http://example.com/stockquote.wsdl}GetTradePricesOutput' self.assertListEqual(list(wsdl_document.messages), [message1_name, message2_name]) message1 = wsdl_document.messages[message1_name] message2 = wsdl_document.messages[message2_name] self.assertListEqual(list(message1.parts), ['tickerSymbol', 'timePeriod']) self.assertListEqual(list(message2.parts), ['result', 'frequency']) port_type_name = '{http://example.com/stockquote.wsdl}StockQuotePortType' self.assertListEqual(list(wsdl_document.port_types), [port_type_name]) port_type = wsdl_document.port_types[port_type_name] self.assertEqual(list(port_type.operations), [('GetTradePrices', None, None)]) operation = port_type.operations[('GetTradePrices', None, None)] self.assertIsNotNone(operation.soap_operation) self.assertEqual(operation.soap_action, 'http://example.com/GetTradePrices') self.assertIs(operation.input.message, message1) self.assertIs(operation.output.message, message2) self.assertEqual(operation.input.soap_body.use, 'encoded') self.assertEqual(operation.input.soap_body.namespace, 'http://example.com/stockquote') self.assertEqual(operation.input.soap_body.encoding_style, 'http://schemas.xmlsoap.org/soap/encoding/') self.assertEqual(len(operation.input.soap_headers), 0) self.assertEqual(operation.output.soap_body.use, 'encoded') self.assertEqual(operation.output.soap_body.namespace, 'http://example.com/stockquote') self.assertEqual(operation.output.soap_body.encoding_style, 'http://schemas.xmlsoap.org/soap/encoding/') self.assertEqual(len(operation.output.soap_headers), 0) binding_name = '{http://example.com/stockquote.wsdl}StockQuoteBinding' self.assertListEqual(list(wsdl_document.bindings), [binding_name]) binding = wsdl_document.bindings[binding_name] self.assertIs(binding.port_type, port_type) self.assertEqual(binding.soap_transport, "http://schemas.xmlsoap.org/soap/http") self.assertEqual(binding.soap_style, "rpc") service_name = '{http://example.com/stockquote.wsdl}StockQuoteService' self.assertListEqual(list(wsdl_document.services), [service_name]) self.assertEqual(list(wsdl_document.services[service_name].ports), ['StockQuotePort']) port = wsdl_document.services[service_name].ports['StockQuotePort'] self.assertEqual(port.soap_location, 'http://example.com/stockquote') def test_wsdl_document_imports(self): stockquote_file = casepath('examples/stockquote/stockquote.wsdl') wsdl_document = Wsdl11Document(stockquote_file) self.assertEqual(wsdl_document.target_namespace, "http://example.com/stockquote/definitions") self.assertIn('http://example.com/stockquote/schemas', wsdl_document.imports) self.assertIsInstance( wsdl_document.imports['http://example.com/stockquote/schemas'], Wsdl11Document ) self.assertEqual(len(wsdl_document.maps.messages), 2) wsdl_document._parse_imports() self.assertListEqual(list(wsdl_document.imports), [ 'http://example.com/stockquote/schemas', ]) stockquote_service_file = casepath('examples/stockquote/stockquoteservice.wsdl') wsdl_document = Wsdl11Document(stockquote_service_file) self.assertListEqual(list(wsdl_document.imports), [ 'http://example.com/stockquote/schemas', 'http://example.com/stockquote/definitions' ]) def test_wsdl_document_invalid_imports(self): wsdl_template = """<?xml version="1.0"?> <definitions name="import-test1" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/ns" location="{0}"/> </definitions>""" wsdl_document = Wsdl11Document(wsdl_template.format('')) self.assertIsNone(wsdl_document.imports['http://example.com/ns']) with self.assertRaises(WsdlParseError) as ctx: Wsdl11Document(wsdl_template.format('missing-file')) self.assertIn('import of namespace', str(ctx.exception)) locations = [('http://example.com/ns', 'missing-file2')] with self.assertRaises(WsdlParseError) as ctx: Wsdl11Document(wsdl_template.format('missing-file'), locations=locations) self.assertIn('import of namespace', str(ctx.exception)) malformed_file = casepath('resources/malformed.xml') with self.assertRaises(WsdlParseError) as ctx: Wsdl11Document(wsdl_template.format(malformed_file)) self.assertIn('cannot import namespace', str(ctx.exception)) self.assertIn('no element found', str(ctx.exception)) wsdl_template = """<?xml version="1.0"?> <definitions name="import-test1" targetNamespace="http://example.com/ns" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/ns" location="{0}"/> </definitions>""" stockquote_file = casepath('examples/stockquote/stockquote.wsdl') with self.assertRaises(WsdlParseError) as ctx: Wsdl11Document(wsdl_template.format(stockquote_file)) self.assertIn('namespace to import must be different', str(ctx.exception)) wsdl_template = """<?xml version="1.0"?> <definitions name="import-test1" targetNamespace="http://example.com/stockquote/definitions" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://example.com/ns" location="{0}"/> </definitions>""" with self.assertRaises(WsdlParseError) as ctx: Wsdl11Document(wsdl_template.format(stockquote_file)) self.assertIn('imported Wsdl11Document', str(ctx.exception)) self.assertIn('has an unmatched namespace', str(ctx.exception)) def test_wsdl_document_maps(self): stockquote_file = casepath('examples/stockquote/stockquote.wsdl') wsdl_document = Wsdl11Document(stockquote_file) self.assertListEqual(list(wsdl_document.maps.imports), ['http://example.com/stockquote/schemas']) self.assertEqual(len(wsdl_document.maps.messages), 2) self.assertEqual(len(wsdl_document.maps.port_types), 1) self.assertEqual(len(wsdl_document.maps.bindings), 0) self.assertEqual(len(wsdl_document.maps.services), 0) wsdl_document.maps.clear() self.assertListEqual(list(wsdl_document.maps.imports), []) self.assertEqual(len(wsdl_document.maps.messages), 0) wsdl_document.parse(stockquote_file) self.assertListEqual(list(wsdl_document.maps.imports), ['http://example.com/stockquote/schemas']) self.assertEqual(len(wsdl_document.maps.messages), 2) stockquote_service_file = casepath('examples/stockquote/stockquoteservice.wsdl') wsdl_document = Wsdl11Document(stockquote_service_file) self.assertListEqual(list(wsdl_document.maps.imports), ['http://example.com/stockquote/schemas', 'http://example.com/stockquote/definitions']) self.assertEqual(len(wsdl_document.maps.messages), 2) self.assertEqual(len(wsdl_document.maps.port_types), 1) self.assertEqual(len(wsdl_document.maps.bindings), 1) self.assertEqual(len(wsdl_document.maps.services), 1) with self.assertRaises(WsdlParseError) as ctx: wsdl_document.parse(stockquote_file, lazy=True) self.assertIn('instance cannot be lazy', str(ctx.exception)) wsdl_document.parse(stockquote_file) self.assertListEqual(list(wsdl_document.maps.imports), ['http://example.com/stockquote/schemas']) self.assertEqual(len(wsdl_document.maps.messages), 2) self.assertEqual(len(wsdl_document.maps.port_types), 1) self.assertEqual(len(wsdl_document.maps.bindings), 0) self.assertEqual(len(wsdl_document.maps.services), 0) wsdl_document.parse(stockquote_service_file) self.assertListEqual(list(wsdl_document.maps.imports), ['http://example.com/stockquote/schemas', 'http://example.com/stockquote/definitions']) self.assertEqual(len(wsdl_document.maps.messages), 2) self.assertEqual(len(wsdl_document.maps.port_types), 1) self.assertEqual(len(wsdl_document.maps.bindings), 1) self.assertEqual(len(wsdl_document.maps.services), 1) def test_wsdl_component(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) elem = ElementTree.Element('foo', bar='abc') wsdl_component = WsdlComponent(elem, wsdl_document) self.assertIsNone(wsdl_component.prefixed_name) self.assertIs(wsdl_component.attrib, elem.attrib) self.assertEqual(wsdl_component.get('bar'), 'abc') elem = ElementTree.Element('foo', name='bar') wsdl_component = WsdlComponent(elem, wsdl_document) self.assertEqual(wsdl_component.prefixed_name, 'tns:bar') self.assertEqual(wsdl_component.map_qname('{http://example.com/stockquote.wsdl}bar'), 'tns:bar') self.assertEqual(wsdl_component.unmap_qname('tns:bar'), '{http://example.com/stockquote.wsdl}bar') elem = ElementTree.Element('foo', a1='tns:bar', a2='unknown:bar') self.assertEqual(wsdl_component._parse_reference(elem, 'a1'), '{http://example.com/stockquote.wsdl}bar') self.assertEqual(wsdl_component._parse_reference(elem, 'a2'), 'unknown:bar') self.assertIsNone(wsdl_component._parse_reference(elem, 'a3')) def test_wsdl_message(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) with self.assertRaises(WsdlParseError) as ctx: wsdl_document._parse_messages() self.assertIn("duplicated message 'tns:GetLastTradePriceInput'", str(ctx.exception)) elem = ElementTree.XML('<message xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' name="GetLastTradePriceInput">\n' ' <part name="body" element="xsd1:unknown"/>\n' '</message>') with self.assertRaises(WsdlParseError) as ctx: WsdlMessage(elem, wsdl_document) self.assertIn('missing schema element', str(ctx.exception)) elem[0].attrib['element'] = 'xsd1:TradePriceRequest' wsdl_message = WsdlMessage(elem, wsdl_document) self.assertEqual(list(wsdl_message.parts), ['body']) elem.append(elem[0]) with self.assertRaises(WsdlParseError) as ctx: WsdlMessage(elem, wsdl_document) self.assertIn("duplicated part 'body'", str(ctx.exception)) elem[0].attrib['type'] = 'xsd1:TradePriceRequest' with self.assertRaises(WsdlParseError) as ctx: WsdlMessage(elem, wsdl_document) self.assertIn("ambiguous binding", str(ctx.exception)) del elem[0].attrib['name'] wsdl_message = WsdlMessage(elem, wsdl_document) self.assertEqual(wsdl_message.parts, {}) elem = ElementTree.XML('<message xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:xs="http://www.w3.org/2001/XMLSchema"\n' ' name="GetLastTradePriceInput">\n' ' <part name="body" type="xs:string"/>\n' '</message>') with self.assertRaises(WsdlParseError) as ctx: WsdlMessage(elem, wsdl_document) self.assertIn('missing schema type', str(ctx.exception)) wsdl_document.namespaces['xs'] = "http://www.w3.org/2001/XMLSchema" wsdl_message = WsdlMessage(elem, wsdl_document) self.assertEqual(list(wsdl_message.parts), ['body']) del elem[0].attrib['type'] with self.assertRaises(WsdlParseError) as ctx: WsdlMessage(elem, wsdl_document) self.assertEqual("missing both 'type' and 'element' attributes", str(ctx.exception)) def test_wsdl_port_type(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) with self.assertRaises(WsdlParseError) as ctx: wsdl_document._parse_port_types() self.assertIn("duplicated port type 'tns:StockQuotePortType'", str(ctx.exception)) elem = ElementTree.XML('<portType xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' name="StockQuotePortType">\n' ' <operation name="GetLastTradePrice">\n' ' <input message="tns:GetLastTradePriceInput"/>\n' ' <output message="tns:GetLastTradePriceOutput"/>\n' ' </operation>\n' '</portType>') wsdl_port_type = WsdlPortType(elem, wsdl_document) self.assertEqual(list(wsdl_port_type.operations), [('GetLastTradePrice', None, None)]) elem.append(elem[0]) # Duplicate operation ... with self.assertRaises(WsdlParseError) as ctx: WsdlPortType(elem, wsdl_document) self.assertIn('duplicated operation', str(ctx.exception)) del elem[0].attrib['name'] wsdl_port_type = WsdlPortType(elem, wsdl_document) self.assertEqual(list(wsdl_port_type.operations), []) def test_wsdl_operation(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) elem = ElementTree.XML('<operation xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' name="GetLastTradePrice">\n' ' <input name="input" message="tns:GetLastTradePriceInput"/>\n' ' <output message="tns:GetLastTradePriceOutput"/>\n' '</operation>') wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.key, ('GetLastTradePrice', 'input', None)) self.assertEqual(wsdl_operation.transmission, 'request-response') elem[1].attrib['name'] = 'output' wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.key, ('GetLastTradePrice', 'input', 'output')) # Check the missing of soap bindings self.assertIsNone(wsdl_operation.soap_operation) self.assertIsNone(wsdl_operation.soap_action) self.assertIsNone(wsdl_operation.soap_style) elem = ElementTree.XML('<operation xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' name="GetLastTradePrice">\n' ' <output name="send" message="tns:GetLastTradePriceOutput"/>\n' ' <input name="receive" message="tns:GetLastTradePriceInput"/>\n' '</operation>') wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.key, ('GetLastTradePrice', 'receive', 'send')) self.assertEqual(wsdl_operation.transmission, 'solicit-response') elem = ElementTree.XML('<operation xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' name="GetLastTradePrice">\n' ' <input message="tns:GetLastTradePriceInput"/>\n' '</operation>') wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.key, ('GetLastTradePrice', None, None)) self.assertEqual(wsdl_operation.transmission, 'one-way') elem = ElementTree.XML('<operation xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' name="GetLastTradePrice">\n' ' <output message="tns:GetLastTradePriceOutput"/>\n' '</operation>') wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.key, ('GetLastTradePrice', None, None)) self.assertEqual(wsdl_operation.transmission, 'notification') # Only for testing code, with faults is better to add specific messages. elem = ElementTree.XML('<operation xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' name="GetLastTradePrice">\n' ' <input message="tns:GetLastTradePriceInput"/>\n' ' <fault message="tns:GetLastTradePriceInput"/>\n' '</operation>') wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(wsdl_operation.faults, {}) # not inserted if name is missing ... elem[1].attrib['name'] = 'foo' wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertEqual(list(wsdl_operation.faults), ['foo']) message_name = '{http://example.com/stockquote.wsdl}GetLastTradePriceInput' message = wsdl_document.messages[message_name] self.assertIs(wsdl_operation.faults['foo'].message, message) elem.append(elem[1]) # create a fake duplicated fault with self.assertRaises(WsdlParseError) as ctx: WsdlOperation(elem, wsdl_document) self.assertIn("duplicated fault 'foo'", str(ctx.exception)) elem.clear() wsdl_operation = WsdlOperation(elem, wsdl_document) self.assertIsNone(wsdl_operation.input) self.assertIsNone(wsdl_operation.output) self.assertIsNone(wsdl_operation.transmission) self.assertEqual(wsdl_operation.faults, {}) def test_wsdl_binding(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) with self.assertRaises(WsdlParseError) as ctx: wsdl_document._parse_bindings() self.assertIn("duplicated binding 'tns:StockQuoteBinding'", str(ctx.exception)) elem = ElementTree.XML( '<binding xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"\n' ' name="StockQuoteBinding" type="tns:StockQuotePortType"\n>' ' <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>\n' ' <operation name="GetLastTradePrice">' ' <input/>' ' <output/>' ' <fault><soap:fault name=""/></fault>' ' </operation>' '</binding>') wsdl_binding = WsdlBinding(elem, wsdl_document) self.assertEqual(wsdl_binding.port_type, list(wsdl_document.port_types.values())[0]) self.assertEqual(list(wsdl_binding.operations), [('GetLastTradePrice', None, None)]) del elem[1][0] # remove <input/> wsdl_binding = WsdlBinding(elem, wsdl_document) self.assertEqual(wsdl_binding.port_type, list(wsdl_document.port_types.values())[0]) self.assertEqual(list(wsdl_binding.operations), [('GetLastTradePrice', None, None)]) del elem[1][0] # remove <output/> wsdl_binding = WsdlBinding(elem, wsdl_document) self.assertEqual(wsdl_binding.port_type, list(wsdl_document.port_types.values())[0]) self.assertEqual(list(wsdl_binding.operations), [('GetLastTradePrice', None, None)]) elem[1][0].attrib['name'] = 'unknown' # set an unknown name to <fault/> with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("missing fault 'unknown'", str(ctx.exception)) del elem[1][0] # remove <fault/> elem.append(elem[1]) with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("duplicated operation 'GetLastTradePrice'", str(ctx.exception)) del elem[2] elem[1].attrib['name'] = 'unknown' with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("operation 'unknown' not found", str(ctx.exception)) del elem[1].attrib['name'] wsdl_binding = WsdlBinding(elem, wsdl_document) self.assertEqual(wsdl_binding.operations, {}) elem.attrib['type'] = 'tns:unknown' with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("missing port type", str(ctx.exception)) del elem[0] with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("missing soap:binding element", str(ctx.exception)) def test_wsdl_service(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) with self.assertRaises(WsdlParseError) as ctx: wsdl_document._parse_services() self.assertIn("duplicated service 'tns:StockQuoteService'", str(ctx.exception)) elem = ElementTree.XML( '<service xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"\n' ' name="StockQuoteService"\n>' ' <port name="StockQuotePort" binding="tns:StockQuoteBinding">' ' <soap:address location="http://example.com/stockquote"/>' ' </port>' '</service>') wsdl_service = WsdlService(elem, wsdl_document) binding_name = '{http://example.com/stockquote.wsdl}StockQuoteBinding' binding = wsdl_document.bindings[binding_name] self.assertIs(wsdl_service.ports['StockQuotePort'].binding, binding) elem[0].attrib['binding'] = 'tns:unknown' with self.assertRaises(WsdlParseError) as ctx: WsdlService(elem, wsdl_document) self.assertIn('unknown binding', str(ctx.exception)) del elem[0].attrib['binding'] wsdl_service = WsdlService(elem, wsdl_document) self.assertIsNone(wsdl_service.ports['StockQuotePort'].binding) self.assertEqual(wsdl_service.ports['StockQuotePort'].soap_location, 'http://example.com/stockquote') del elem[0][0] wsdl_service = WsdlService(elem, wsdl_document) self.assertIsNone(wsdl_service.ports['StockQuotePort'].soap_location) elem.append(elem[0]) with self.assertRaises(WsdlParseError) as ctx: WsdlService(elem, wsdl_document) self.assertIn('duplicated port', str(ctx.exception)) del elem[0].attrib['name'] wsdl_service = WsdlService(elem, wsdl_document) self.assertEqual(wsdl_service.ports, {}) def test_wsdl_missing_message_reference(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) elem = ElementTree.XML('<input xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' message="tns:unknown"/>') with self.assertRaises(WsdlParseError) as ctx: WsdlInput(elem, wsdl_document) self.assertIn('unknown message', str(ctx.exception)) elem = ElementTree.XML('<input xmlns="http://schemas.xmlsoap.org/wsdl/"/>') input_op = WsdlInput(elem, wsdl_document) self.assertIsNone(input_op.message) def test_wsdl_soap_header_bindings(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_EXAMPLE) elem = ElementTree.XML('<header xmlns="http://schemas.xmlsoap.org/wsdl/soap/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' message="tns:SubscribeToQuotes"\n' ' part="subscribeheader" use="literal"/>') with self.assertRaises(WsdlParseError) as ctx: SoapHeader(elem, wsdl_document) self.assertIn('unknown message', str(ctx.exception)) elem.attrib['message'] = 'tns:GetLastTradePriceInput' with self.assertRaises(WsdlParseError) as ctx: SoapHeader(elem, wsdl_document) self.assertIn("missing message part 'subscribeheader'", str(ctx.exception)) elem.attrib['part'] = 'body' soap_header = SoapHeader(elem, wsdl_document) message_name = '{http://example.com/stockquote.wsdl}GetLastTradePriceInput' self.assertIs(wsdl_document.messages[message_name], soap_header.message) self.assertIs(wsdl_document.messages[message_name].parts['body'], soap_header.part) del elem.attrib['part'] soap_header = SoapHeader(elem, wsdl_document) self.assertIs(wsdl_document.messages[message_name], soap_header.message) self.assertIsNone(soap_header.part) elem = ElementTree.XML('<header xmlns="http://schemas.xmlsoap.org/wsdl/soap/"\n' ' xmlns:tns="http://example.com/stockquote.wsdl"\n' ' message="tns:GetLastTradePriceInput"\n' ' part="body" use="literal">\n' ' <headerfault message="tns:GetLastTradePriceInput"\n' ' part="body" use="literal"/>\n' '</header>') soap_header = SoapHeader(elem, wsdl_document) message = wsdl_document.messages[message_name] self.assertIs(message, soap_header.message) self.assertIs(message.parts['body'], soap_header.part) self.assertEqual(len(soap_header.faults), 1) self.assertIs(message, soap_header.faults[0].message) self.assertIs(message.parts['body'], soap_header.faults[0].part) def test_wsdl_no_soap_bindings(self): wsdl_document = Wsdl11Document(WSDL_DOCUMENT_NO_SOAP) self.assertEqual(list(wsdl_document.messages), ['myMessage']) self.assertEqual(list(wsdl_document.port_types), ['myPortType']) self.assertEqual(list(wsdl_document.bindings), ['myBinding']) self.assertEqual(list(wsdl_document.services), ['myService']) self.assertIsNone(wsdl_document.bindings['myBinding'].soap_transport) self.assertIsNone(wsdl_document.bindings['myBinding'].soap_style) def test_wsdl_and_soap_faults(self): example5_file_with_fault = casepath('features/wsdl/wsdl11_example5_with_fault.wsdl') wsdl_document = Wsdl11Document(example5_file_with_fault) port_type_name = '{http://example.com/stockquote.wsdl}StockQuotePortType' self.assertListEqual(list(wsdl_document.port_types), [port_type_name]) port_type = wsdl_document.port_types[port_type_name] operation = port_type.operations[('GetTradePrices', None, None)] message_name = '{http://example.com/stockquote.wsdl}FaultMessage' message = wsdl_document.messages[message_name] self.assertIs(operation.faults['fault'].message, message) elem = ElementTree.XML( '<binding xmlns="http://schemas.xmlsoap.org/wsdl/"\n' ' xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"\n' ' name="StockQuoteBinding" type="tns:StockQuotePortType"\n>' ' <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>\n' ' <operation name="GetTradePrices">' ' <input/>' ' <output/>' ' <fault><soap:fault name="exception"/></fault>' ' </operation>' '</binding>') with self.assertRaises(WsdlParseError) as ctx: WsdlBinding(elem, wsdl_document) self.assertIn("missing fault 'exception'", str(ctx.exception)) def test_loading_from_unrelated_dirs__issue_237(self): relpath = str(pathlib.Path(__file__).parent.joinpath( 'test_cases/issues/issue_237/dir1/stockquoteservice.wsdl' )) wsdl_document = Wsdl11Document(relpath) self.assertIn('http://example.com/stockquote/schemas', wsdl_document.imports) self.assertEqual( wsdl_document.imports['http://example.com/stockquote/schemas'].name, 'stockquote.xsd' ) self.assertIn('http://example.com/stockquote/definitions', wsdl_document.imports) self.assertEqual( wsdl_document.imports['http://example.com/stockquote/definitions'].name, 'stockquote.wsdl' ) if __name__ == '__main__': import platform header_template = "Test xmlschema WSDL documents with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������xmlschema-1.10.0/tests/test_xpath.py����������������������������������������������������������������0000664�0000000�0000000�00000040112�14211403446�0017446�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests for XPath parsing and selectors""" import unittest import os import pathlib from elementpath import XPath1Parser, XPath2Parser, Selector, \ AttributeNode, TypedElement, ElementPathSyntaxError from xmlschema import XMLSchema10, XMLSchema11, XsdElement, XsdAttribute from xmlschema.names import XSD_NAMESPACE from xmlschema.etree import ElementTree from xmlschema.xpath import XMLSchemaProxy, iter_schema_nodes, XPathElement from xmlschema.validators import XsdAtomic, XsdAtomicRestriction CASES_DIR = os.path.join(os.path.dirname(__file__), 'test_cases/') class XMLSchemaProxyTest(unittest.TestCase): schema_class = XMLSchema10 @classmethod def setUpClass(cls): cls.xs1 = cls.schema_class(os.path.join(CASES_DIR, "examples/vehicles/vehicles.xsd")) cls.xs2 = cls.schema_class(os.path.join(CASES_DIR, "examples/collection/collection.xsd")) cls.xs3 = cls.schema_class(os.path.join(CASES_DIR, "features/decoder/simple-types.xsd")) def test_initialization(self): schema_proxy = XMLSchemaProxy() self.assertIs(schema_proxy._schema, self.schema_class.meta_schema) schema_proxy = XMLSchemaProxy(self.xs1, base_element=self.xs1.elements['vehicles']) self.assertIs(schema_proxy._schema, self.xs1) with self.assertRaises(ValueError): XMLSchemaProxy(self.xs1, base_element=self.xs2.elements['collection']) with self.assertRaises(TypeError): XMLSchemaProxy(self.xs1, base_element=ElementTree.Element('vehicles')) def test_bind_parser_method(self): schema_proxy1 = XMLSchemaProxy(self.xs1) schema_proxy2 = XMLSchemaProxy(self.xs2) parser = XPath2Parser(strict=False, schema=schema_proxy1) self.assertIs(parser.schema, schema_proxy1) schema_proxy1.bind_parser(parser) self.assertIs(parser.schema, schema_proxy1) schema_proxy2.bind_parser(parser) self.assertIs(parser.schema, schema_proxy2) def test_get_context_method(self): schema_proxy = XMLSchemaProxy(self.xs1) context = schema_proxy.get_context() self.assertIs(context.root, self.xs1) def test_get_type_method(self): schema_proxy = XMLSchemaProxy(self.xs1) qname = '{%s}vehicleType' % self.xs1.target_namespace self.assertIs(schema_proxy.get_type(qname), self.xs1.types['vehicleType']) qname = '{%s}unknown' % self.xs1.target_namespace self.assertIsNone(schema_proxy.get_type(qname)) def test_get_attribute_method(self): schema_proxy = XMLSchemaProxy(self.xs1) qname = '{%s}step' % self.xs1.target_namespace self.assertIs(schema_proxy.get_attribute(qname), self.xs1.attributes['step']) qname = '{%s}unknown' % self.xs1.target_namespace self.assertIsNone(schema_proxy.get_attribute(qname)) def test_get_element_method(self): schema_proxy = XMLSchemaProxy(self.xs1) qname = '{%s}cars' % self.xs1.target_namespace self.assertIs(schema_proxy.get_element(qname), self.xs1.elements['cars']) qname = '{%s}unknown' % self.xs1.target_namespace self.assertIsNone(schema_proxy.get_element(qname)) def test_get_substitution_group_method(self): schema = XMLSchema11.meta_schema schema.build() schema_proxy = XMLSchemaProxy(schema) qname = '{%s}facet' % schema.target_namespace self.assertIs(schema_proxy.get_substitution_group(qname), schema.substitution_groups['facet']) qname = '{%s}unknown' % schema.target_namespace self.assertIsNone(schema_proxy.get_substitution_group(qname)) def test_find_method(self): schema_proxy = XMLSchemaProxy(self.xs1) qname = '{%s}cars' % self.xs1.target_namespace self.assertIs(schema_proxy.find(qname), self.xs1.elements['cars']) def test_is_instance_method(self): schema_proxy = XMLSchemaProxy(self.xs1) type_qname = '{%s}string' % self.xs1.meta_schema.target_namespace self.assertFalse(schema_proxy.is_instance(10, type_qname)) self.assertTrue(schema_proxy.is_instance('10', type_qname)) def test_cast_as_method(self): schema_proxy = XMLSchemaProxy(self.xs1) type_qname = '{%s}short' % self.xs1.meta_schema.target_namespace self.assertEqual(schema_proxy.cast_as('10', type_qname), 10) def test_iter_atomic_types_method(self): schema_proxy = XMLSchemaProxy(self.xs3) k = 0 for k, xsd_type in enumerate(schema_proxy.iter_atomic_types(), start=1): self.assertNotIn(XSD_NAMESPACE, xsd_type.name) self.assertIsInstance(xsd_type, (XsdAtomic, XsdAtomicRestriction)) self.assertGreater(k, 10) def test_get_primitive_type_method(self): schema_proxy = XMLSchemaProxy(self.xs3) string_type = self.xs3.meta_schema.types['string'] xsd_type = self.xs3.types['list_of_strings'] self.assertIs(schema_proxy.get_primitive_type(xsd_type), string_type) xsd_type = self.xs3.types['integer_or_float'] self.assertIs(schema_proxy.get_primitive_type(xsd_type), xsd_type) def test_iter_schema_nodes_function(self): vh_elements = set(e for e in self.xs1.maps.iter_components(XsdElement) if e.target_namespace == self.xs1.target_namespace) self.assertEqual(set(iter_schema_nodes(self.xs1)), vh_elements | {self.xs1}) self.assertEqual(set(iter_schema_nodes(self.xs1, with_root=False)), vh_elements) vh_nodes = set() for node in self.xs1.maps.iter_components((XsdElement, XsdAttribute)): if node.target_namespace != self.xs1.target_namespace: continue elif isinstance(node, XsdAttribute): vh_nodes.add(AttributeNode(node.local_name, node)) else: vh_nodes.add(node) cars = self.xs1.elements['cars'] car = self.xs1.find('//vh:car') typed_cars = TypedElement(cars, cars.type, None) self.assertListEqual(list(iter_schema_nodes(cars)), [cars, car]) self.assertListEqual(list(iter_schema_nodes(typed_cars)), [cars, car]) self.assertListEqual(list(iter_schema_nodes(cars, with_root=False)), [car]) self.assertListEqual(list(iter_schema_nodes(typed_cars, with_root=False)), [car]) class XPathElementTest(unittest.TestCase): schema_class = XMLSchema10 col_xsd_path = None @classmethod def setUpClass(cls): cls.col_xsd_path = pathlib.Path(CASES_DIR).joinpath("examples/collection/collection.xsd") cls.col_schema = cls.schema_class(cls.col_xsd_path) def test_is_matching(self): # The mixin method is used by schema class but overridden for XSD components. # A schema has no formal name, so it takes the source's filename, if any. # This does not have effect on validation because schema is the root. self.assertEqual(self.col_schema.default_namespace, 'http://example.com/ns/collection') self.assertEqual(self.col_schema.name, 'collection.xsd') self.assertTrue(self.col_schema.is_matching('collection.xsd')) self.assertFalse( self.col_schema.is_matching('collection.xsd', 'http://example.com/ns/collection') ) def test_iteration(self): elem = XPathElement('foo', self.col_schema.types['objType']) self.assertListEqual( [child.name for child in elem], ['position', 'title', 'year', 'author', 'estimation', 'characters'] ) elem = XPathElement('foo', self.col_schema.builtin_types()['string']) self.assertListEqual(list(elem), []) def test_xpath_proxy(self): elem = XPathElement('foo', self.col_schema.types['objType']) xpath_proxy = elem.xpath_proxy self.assertIsInstance(xpath_proxy, XMLSchemaProxy) self.assertIs(xpath_proxy._schema, self.col_schema) def test_schema(self): elem = XPathElement('foo', self.col_schema.types['objType']) self.assertIs(elem.schema, self.col_schema) self.assertIs(elem.namespaces, self.col_schema.namespaces) def test_target_namespace(self): elem = XPathElement('foo', self.col_schema.types['objType']) self.assertEqual(elem.target_namespace, 'http://example.com/ns/collection') def test_elem_name(self): elem = XPathElement('foo', self.col_schema.types['objType']) try: elem.namespaces['col'] = 'http://example.com/ns/collection' self.assertEqual(elem.local_name, 'foo') self.assertEqual(elem.qualified_name, '{http://example.com/ns/collection}foo') self.assertEqual(elem.prefixed_name, 'foo') elem = XPathElement('{http://example.com/ns/collection}foo', self.col_schema.types['objType']) self.assertEqual(elem.local_name, 'foo') self.assertEqual(elem.qualified_name, '{http://example.com/ns/collection}foo') self.assertEqual(elem.prefixed_name, 'col:foo') finally: elem.namespaces.pop('col') class XMLSchemaXPathTest(unittest.TestCase): schema_class = XMLSchema10 @classmethod def setUpClass(cls): cls.xs1 = cls.schema_class(os.path.join(CASES_DIR, "examples/vehicles/vehicles.xsd")) cls.xs2 = cls.schema_class(os.path.join(CASES_DIR, "examples/collection/collection.xsd")) cls.cars = cls.xs1.elements['vehicles'].type.content[0] cls.bikes = cls.xs1.elements['vehicles'].type.content[1] def test_xpath_wrong_syntax(self): self.assertRaises(ElementPathSyntaxError, self.xs1.find, './*[') self.assertRaises(ElementPathSyntaxError, self.xs1.find, './*)') self.assertRaises(ElementPathSyntaxError, self.xs1.find, './*3') self.assertRaises(ElementPathSyntaxError, self.xs1.find, './@3') def test_xpath_extra_spaces(self): self.assertTrue(self.xs1.find('./ *') is not None) self.assertTrue(self.xs1.find("\t\n vh:vehicles / vh:cars / .. / vh:cars") == self.cars) def test_xpath_location_path(self): elements = sorted(self.xs1.elements.values(), key=lambda x: x.name) self.assertTrue(self.xs1.findall('.')) self.assertTrue(isinstance(self.xs1.find('.'), self.schema_class)) self.assertTrue(sorted(self.xs1.findall("*"), key=lambda x: x.name) == elements) self.assertListEqual(self.xs1.findall("*"), self.xs1.findall("./*")) self.assertEqual(self.xs1.find("./vh:bikes"), self.xs1.elements['bikes']) self.assertEqual(self.xs1.find("./vh:vehicles/vh:cars").name, self.xs1.elements['cars'].name) self.assertNotEqual(self.xs1.find("./vh:vehicles/vh:cars"), self.xs1.elements['cars']) self.assertNotEqual(self.xs1.find("/vh:vehicles/vh:cars"), self.xs1.elements['cars']) self.assertEqual(self.xs1.find("vh:vehicles/vh:cars/.."), self.xs1.elements['vehicles']) self.assertEqual(self.xs1.find("vh:vehicles/*/.."), self.xs1.elements['vehicles']) self.assertEqual(self.xs1.find("vh:vehicles/vh:cars/../vh:cars"), self.xs1.find("vh:vehicles/vh:cars")) def test_xpath_axis(self): self.assertEqual(self.xs1.find("vh:vehicles/child::vh:cars/.."), self.xs1.elements['vehicles']) def test_xpath_subscription(self): self.assertEqual(len(self.xs1.findall("./vh:vehicles/*")), 2) self.assertListEqual(self.xs1.findall("./vh:vehicles/*[2]"), [self.bikes]) self.assertListEqual(self.xs1.findall("./vh:vehicles/*[3]"), []) self.assertListEqual(self.xs1.findall("./vh:vehicles/*[last()-1]"), [self.cars]) self.assertListEqual(self.xs1.findall("./vh:vehicles/*[position()=last()]"), [self.bikes]) def test_xpath_group(self): self.assertEqual(self.xs1.findall("/(vh:vehicles/*/*)"), self.xs1.findall("/vh:vehicles/*/*")) self.assertEqual(self.xs1.findall("/(vh:vehicles/*/*)[1]"), self.xs1.findall("/vh:vehicles/*/*[1]")[:1]) def test_xpath_predicate(self): car = self.xs1.elements['cars'].type.content[0] self.assertListEqual(self.xs1.findall("./vh:vehicles/vh:cars/vh:car[@make]"), [car]) self.assertListEqual(self.xs1.findall("./vh:vehicles/vh:cars/vh:car[@make]"), [car]) self.assertListEqual(self.xs1.findall("./vh:vehicles/vh:cars['ciao']"), [self.cars]) self.assertListEqual(self.xs1.findall("./vh:vehicles/*['']"), []) def test_xpath_descendants(self): selector = Selector('.//xs:element', self.xs2.namespaces, parser=XPath1Parser) elements = list(selector.iter_select(self.xs2.root)) self.assertEqual(len(elements), 14) selector = Selector('.//xs:element|.//xs:attribute|.//xs:keyref', self.xs2.namespaces, parser=XPath1Parser) elements = list(selector.iter_select(self.xs2.root)) self.assertEqual(len(elements), 17) def test_xpath_issues(self): namespaces = {'ps': "http://schemas.microsoft.com/powershell/2004/04"} selector = Selector("./ps:Props/*|./ps:MS/*", namespaces=namespaces, parser=XPath1Parser) self.assertTrue(selector.root_token.tree, '(| (/ (/ (.) (: (ps) (Props))) (*)) (/ (/ (.) (: (ps) (MS))) (*)))') def test_get(self): xsd_element = self.xs1.elements['vehicles'] self.assertIsNone(xsd_element.get('unknown')) self.assertEqual(xsd_element[0][0].get('model'), xsd_element[0][0].attributes['model']) def test_getitem(self): xsd_element = self.xs1.elements['vehicles'] self.assertEqual(xsd_element[0], xsd_element.type.content[0]) self.assertEqual(xsd_element[1], xsd_element.type.content[1]) with self.assertRaises(IndexError): _ = xsd_element[2] def test_reversed(self): xsd_element = self.xs1.elements['vehicles'] self.assertListEqual( list(reversed(xsd_element)), [xsd_element.type.content[1], xsd_element.type.content[0]] ) def test_iterfind(self): car = self.xs1.find('//vh:car') bike = self.xs1.find('//vh:bike') self.assertIsNotNone(car) self.assertIsNotNone(bike) self.assertListEqual(list(self.xs1.iterfind("/(vh:vehicles/*/*)")), [car, bike]) def test_iter(self): xsd_element = self.xs1.elements['vehicles'] descendants = list(xsd_element.iter()) self.assertListEqual(descendants, [xsd_element] + xsd_element.type.content[:]) descendants = list(xsd_element.iter('*')) self.assertListEqual(descendants, [xsd_element] + xsd_element.type.content[:]) descendants = list(xsd_element.iter(self.xs1.elements['cars'].name)) self.assertListEqual(descendants, [xsd_element.type.content[0]]) def test_iterchildren(self): children = list(self.xs1.elements['vehicles'].iterchildren()) self.assertListEqual(children, self.xs1.elements['vehicles'].type.content[:]) children = list(self.xs1.elements['vehicles'].iterchildren('*')) self.assertListEqual(children, self.xs1.elements['vehicles'].type.content[:]) children = list(self.xs1.elements['vehicles'].iterchildren(self.xs1.elements['bikes'].name)) self.assertListEqual(children, self.xs1.elements['vehicles'].type.content[1:]) class ElementTreeXPathTest(unittest.TestCase): def test_rel_xpath_boolean(self): root = ElementTree.XML('<A><B><C/></B></A>') el = root[0] self.assertTrue(Selector('boolean(C)').iter_select(el)) self.assertFalse(next(Selector('boolean(D)').iter_select(el))) if __name__ == '__main__': import platform header_template = "Test xmlschema XPath with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validation/������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017045�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validation/__init__.py�������������������������������������������������������0000664�0000000�0000000�00000000000�14211403446�0021144�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validation/test_decoding.py��������������������������������������������������0000664�0000000�0000000�00000153626�14211403446�0022247�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ #!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import json from decimal import Decimal from collections.abc import MutableMapping, MutableSequence, Set import base64 try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from elementpath import datatypes import xmlschema from xmlschema import XMLSchemaValidationError, ParkerConverter, BadgerFishConverter, \ AbderaConverter, JsonMLConverter, ColumnarConverter from xmlschema.names import XSD_STRING from xmlschema.etree import ElementTree from xmlschema.converters import UnorderedConverter from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase, etree_elements_assert_equal VEHICLES_DICT = { '@xmlns:vh': 'http://example.com/vehicles', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd', 'vh:cars': { 'vh:car': [ {'@make': 'Porsche', '@model': '911'}, {'@make': 'Porsche', '@model': '911'} ]}, 'vh:bikes': { 'vh:bike': [ {'@make': 'Harley-Davidson', '@model': 'WL'}, {'@make': 'Yamaha', '@model': 'XS650'} ]} } VEHICLES_DICT_ALT = [ {'vh:cars': [ {'vh:car': None, '@make': 'Porsche', '@model': '911'}, {'vh:car': None, '@make': 'Porsche', '@model': '911'} ]}, {'vh:bikes': [ {'vh:bike': None, '@make': 'Harley-Davidson', '@model': 'WL'}, {'vh:bike': None, '@make': 'Yamaha', '@model': 'XS650'} ]}, {'@xsi:schemaLocation': 'http://example.com/vehicles vehicles.xsd'} ] COLLECTION_DICT = { '@xmlns:col': 'http://example.com/ns/collection', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{ '@available': True, '@id': 'b0836217462', 'author': { '@id': 'PAR', 'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter' }, 'estimation': Decimal('10000.00'), 'position': 1, 'title': 'The Umbrellas', 'year': '1886'}, { '@available': True, '@id': 'b0836217463', 'author': { '@id': 'JM', 'born': '1893-04-20', 'dead': '1983-12-25', 'name': u'Joan Miró', 'qualification': 'painter, sculptor and ceramicist' }, 'position': 2, 'title': None, 'year': '1925' }] } COLLECTION_PARKER = { 'object': [{'author': {'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter'}, 'estimation': 10000.0, 'position': 1, 'title': 'The Umbrellas', 'year': '1886'}, {'author': {'born': '1893-04-20', 'dead': '1983-12-25', 'name': u'Joan Miró', 'qualification': 'painter, sculptor and ceramicist'}, 'position': 2, 'title': None, 'year': '1925'}]} COLLECTION_PARKER_ROOT = { 'col:collection': {'object': [{'author': {'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter'}, 'estimation': 10000.0, 'position': 1, 'title': 'The Umbrellas', 'year': '1886'}, {'author': {'born': '1893-04-20', 'dead': '1983-12-25', 'name': u'Joan Miró', 'qualification': 'painter, sculptor and ceramicist'}, 'position': 2, 'title': None, 'year': '1925'}]}} COLLECTION_BADGERFISH = { '@xmlns': { 'col': 'http://example.com/ns/collection', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'}, 'col:collection': { '@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{ '@available': True, '@id': 'b0836217462', 'author': { '@id': 'PAR', 'born': {'$': '1841-02-25'}, 'dead': {'$': '1919-12-03'}, 'name': {'$': 'Pierre-Auguste Renoir'}, 'qualification': {'$': 'painter'}}, 'estimation': {'$': 10000.0}, 'position': {'$': 1}, 'title': {'$': 'The Umbrellas'}, 'year': {'$': '1886'}}, { '@available': True, '@id': 'b0836217463', 'author': { '@id': 'JM', 'born': {'$': '1893-04-20'}, 'dead': {'$': '1983-12-25'}, 'name': {'$': u'Joan Miró'}, 'qualification': { '$': 'painter, sculptor and ceramicist'} }, 'position': {'$': 2}, 'title': {}, 'year': {'$': '1925'} }] } } COLLECTION_ABDERA = { 'attributes': { 'xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd' }, 'children': [ { 'object': [ { 'attributes': {'available': True, 'id': 'b0836217462'}, 'children': [{ 'author': { 'attributes': {'id': 'PAR'}, 'children': [{ 'born': '1841-02-25', 'dead': '1919-12-03', 'name': 'Pierre-Auguste Renoir', 'qualification': 'painter'} ]}, 'estimation': 10000.0, 'position': 1, 'title': 'The Umbrellas', 'year': '1886'} ]}, { 'attributes': {'available': True, 'id': 'b0836217463'}, 'children': [{ 'author': { 'attributes': {'id': 'JM'}, 'children': [{ 'born': '1893-04-20', 'dead': '1983-12-25', 'name': u'Joan Miró', 'qualification': 'painter, sculptor and ceramicist'} ]}, 'position': 2, 'title': [], 'year': '1925' }] }] } ]} COLLECTION_JSON_ML = [ 'col:collection', {'xmlns:col': 'http://example.com/ns/collection', 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd'}, ['object', {'available': True, 'id': 'b0836217462'}, ['position', 1], ['title', 'The Umbrellas'], ['year', '1886'], [ 'author', {'id': 'PAR'}, ['name', 'Pierre-Auguste Renoir'], ['born', '1841-02-25'], ['dead', '1919-12-03'], ['qualification', 'painter'] ], [ 'estimation', Decimal('10000.00') ]], ['object', {'available': True, 'id': 'b0836217463'}, ['position', 2], ['title'], ['year', '1925'], [ 'author', {'id': 'JM'}, ['name', u'Joan Miró'], ['born', '1893-04-20'], ['dead', '1983-12-25'], ['qualification', 'painter, sculptor and ceramicist'] ]] ] COLLECTION_COLUMNAR = { 'collection': { 'collectionxsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{ 'objectid': 'b0836217462', 'objectavailable': True, 'position': 1, 'title': 'The Umbrellas', 'year': '1886', 'author': { 'authorid': 'PAR', 'name': 'Pierre-Auguste Renoir', 'born': '1841-02-25', 'dead': '1919-12-03', 'qualification': 'painter' }, 'estimation': Decimal('10000.00')}, { 'objectid': 'b0836217463', 'objectavailable': True, 'position': 2, 'title': None, 'year': '1925', 'author': { 'authorid': 'JM', 'name': 'Joan Miró', 'born': '1893-04-20', 'dead': '1983-12-25', 'qualification': 'painter, sculptor and ceramicist' } }] } } COLLECTION_COLUMNAR_ = { 'collection': { 'collection_xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{ 'object_id': 'b0836217462', 'object_available': True, 'position': 1, 'title': 'The Umbrellas', 'year': '1886', 'author': { 'author_id': 'PAR', 'name': 'Pierre-Auguste Renoir', 'born': '1841-02-25', 'dead': '1919-12-03', 'qualification': 'painter' }, 'estimation': Decimal('10000.00')}, { 'object_id': 'b0836217463', 'object_available': True, 'position': 2, 'title': None, 'year': '1925', 'author': { 'author_id': 'JM', 'name': 'Joan Miró', 'born': '1893-04-20', 'dead': '1983-12-25', 'qualification': 'painter, sculptor and ceramicist' } }] } } DATA_DICT = { '@xmlns:ns': 'ns', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'ns ./simple-types.xsd', 'certification': [ {'$': 'ISO-9001', '@Year': 1999}, {'$': 'ISO-27001', '@Year': 2009} ], 'decimal_value': [Decimal('1')], 'hexbin': 'AABBCCDD', 'menù': 'baccalà mantecato', 'complex_boolean': [ {'$': True, '@Type': 2}, {'$': False, '@Type': 1}, True, False ], 'simple_boolean': [True, False], 'date_and_time': '2020-03-05T23:04:10.047', # xs:dateTime is not decoded for default } def iter_nested_iterables(obj): if not isinstance(obj, (MutableMapping, MutableSequence, Set, tuple)): yield obj else: for item in obj.values() if isinstance(obj, MutableMapping) else obj: if not isinstance(item, (MutableMapping, MutableSequence, Set, tuple)): yield item else: yield from iter_nested_iterables(item) class TestDecoding(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') def check_decode(self, xsd_component, data, expected, **kwargs): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, xsd_component.decode, data, **kwargs) else: obj = xsd_component.decode(data, **kwargs) if isinstance(obj, tuple) and len(obj) == 2 and isinstance(obj[1], list) \ and isinstance(obj[1][0], Exception): self.assertEqual(expected, obj[0]) self.assertTrue(isinstance(obj[0], type(expected))) else: self.assertEqual(expected, obj) self.assertTrue(isinstance(obj, type(expected))) @unittest.skipIf(lxml_etree is None, "The lxml library is not available.") def test_lxml(self): vh_xml_tree = lxml_etree.parse(self.vh_xml_file) self.assertEqual(self.vh_schema.to_dict(vh_xml_tree), VEHICLES_DICT) self.assertEqual(xmlschema.to_dict(vh_xml_tree, self.vh_schema.url), VEHICLES_DICT) def test_to_dict_from_etree(self): vh_xml_tree = ElementTree.parse(self.vh_xml_file) col_xml_tree = ElementTree.parse(self.col_xml_file) xml_dict = self.vh_schema.to_dict(vh_xml_tree) self.assertNotEqual(xml_dict, VEHICLES_DICT) xml_dict = self.vh_schema.to_dict(vh_xml_tree, namespaces=self.vh_namespaces) self.assertEqual(xml_dict, VEHICLES_DICT) xml_dict = xmlschema.to_dict(vh_xml_tree, self.vh_schema.url, namespaces=self.vh_namespaces) self.assertEqual(xml_dict, VEHICLES_DICT) xml_dict = self.col_schema.to_dict(col_xml_tree) self.assertNotEqual(xml_dict, COLLECTION_DICT) xml_dict = self.col_schema.to_dict(col_xml_tree, namespaces=self.col_namespaces) self.assertEqual(xml_dict, COLLECTION_DICT) xml_dict = xmlschema.to_dict(col_xml_tree, self.col_schema.url, namespaces=self.col_namespaces) self.assertEqual(xml_dict, COLLECTION_DICT) def test_to_dict_from_string(self): with open(self.vh_xml_file) as f: vh_xml_string = f.read() with open(self.col_xml_file) as f: col_xml_string = f.read() xml_dict = self.vh_schema.to_dict(vh_xml_string, namespaces=self.vh_namespaces) self.assertEqual(xml_dict, VEHICLES_DICT) xml_dict = xmlschema.to_dict(vh_xml_string, self.vh_schema.url, namespaces=self.vh_namespaces) self.assertEqual(xml_dict, VEHICLES_DICT) xml_dict = self.col_schema.to_dict(col_xml_string, namespaces=self.col_namespaces) self.assertTrue(xml_dict, COLLECTION_DICT) xml_dict = xmlschema.to_dict(col_xml_string, self.col_schema.url, namespaces=self.col_namespaces) self.assertTrue(xml_dict, COLLECTION_DICT) def test_date_decoding(self): # Issue #136 schema = self.schema_class("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> <xs:element name="Date"> <xs:simpleType> <xs:restriction base="xs:date"> <xs:minInclusive value="2000-01-01"/> <xs:maxInclusive value="2099-12-31"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:schema>""") self.assertEqual(schema.to_dict("<Date>2019-01-01</Date>"), '2019-01-01') self.assertEqual(schema.to_dict("<Date>2019-01-01</Date>", datetime_types=True), datatypes.Date10.fromstring('2019-01-01')) data, errors = schema.to_dict("<Date>2019-01-01</Date>", validation='lax') self.assertEqual(data, '2019-01-01') self.assertEqual(errors, []) data, errors = schema.to_dict("<Date>2019-01-01</Date>", validation='lax', datetime_types=True) self.assertEqual(data, datatypes.Date10.fromstring('2019-01-01')) self.assertEqual(errors, []) data, errors = schema.to_dict("<Date>1999-12-31</Date>", validation='lax') self.assertEqual(data, '1999-12-31') self.assertEqual(len(errors), 1) self.assertIn('value has to be greater or equal than', str(errors[0])) data, errors = schema.to_dict("<Date>1999-12-31</Date>", validation='lax', datetime_types=True) self.assertEqual(data, datatypes.Date10.fromstring('1999-12-31')) self.assertEqual(len(errors), 1) data, errors = schema.to_dict("<Date>2019</Date>", validation='lax') self.assertIsNone(data) self.assertEqual(len(errors), 1) with self.assertRaises(XMLSchemaValidationError): schema.to_dict("<Date>2019</Date>") data, errors = schema.to_dict("<Date>2019</Date>", validation='lax') self.assertIsNone(data) self.assertEqual(len(errors), 1) def test_qname_decoding(self): schema = self.schema_class("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="rootType" /> <xs:complexType name="rootType"> <xs:simpleContent> <xs:extension base="xs:QName"> <xs:attribute name="name" type="xs:QName"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:schema>""") xml_data = '<root xmlns:ns0="http://xmlschema.test/0">ns0:foo</root>' self.assertEqual(schema.decode(xml_data), 'ns0:foo') self.assertEqual(schema.decode('<root>foo</root>'), 'foo') with self.assertRaises(XMLSchemaValidationError) as ctx: schema.decode('<root>ns0:foo</root>') self.assertIn("failed validating 'ns0:foo'", str(ctx.exception)) self.assertIn("Reason: unmapped prefix 'ns0' on QName", str(ctx.exception)) self.assertIn("Path: /root", str(ctx.exception)) xml_data = '<root name="ns0:bar" xmlns:ns0="http://xmlschema.test/0">ns0:foo</root>' self.assertEqual(schema.decode(xml_data), {'@name': 'ns0:bar', '$': 'ns0:foo'}) # Check reverse encoding obj = schema.decode(xml_data, converter=JsonMLConverter) root = schema.encode(obj, converter=JsonMLConverter) self.assertEqual(ElementTree.tostring(root), b'<root name="ns0:bar">ns0:foo</root>\n') with self.assertRaises(XMLSchemaValidationError) as ctx: schema.decode('<root name="ns0:bar">foo</root>') self.assertIn("failed validating 'ns0:bar'", str(ctx.exception)) self.assertIn("unmapped prefix 'ns0' on QName", str(ctx.exception)) self.assertIn("Path: /root", str(ctx.exception)) def test_json_dump_and_load(self): vh_xml_tree = ElementTree.parse(self.vh_xml_file) col_xml_tree = ElementTree.parse(self.col_xml_file) with open(self.vh_json_file, 'w') as f: xmlschema.to_json(self.vh_xml_file, f) with open(self.vh_json_file) as f: root = xmlschema.from_json(f, self.vh_schema) os.remove(self.vh_json_file) self.check_etree_elements(vh_xml_tree.getroot(), root) with open(self.col_json_file, 'w') as f: xmlschema.to_json(self.col_xml_file, f) with open(self.col_json_file) as f: root = xmlschema.from_json(f, self.col_schema) os.remove(self.col_json_file) self.check_etree_elements(col_xml_tree.getroot(), root) def test_json_path_decoding(self): xml_file = self.col_xml_file schema = self.col_schema json_data = xmlschema.to_json(xml_file, schema=schema, path='*') self.assertIsInstance(json_data, str) self.assertEqual(len(json_data), 493) self.assertEqual(json_data[:4], '[{"@') self.assertEqual(json_data[-1], ']') self.assertEqual( json_data, xmlschema.to_json(xml_file, schema=schema, path='object') ) self.assertEqual( json_data, xmlschema.to_json(xml_file, schema=schema, path='//object') ) self.assertEqual( json_data, xmlschema.to_json(xml_file, schema=schema, path='/col:collection/object') ) def test_json_lazy_decoding(self): kwargs = {'xml_document': self.col_xml_file, 'schema': self.col_schema} col_json = xmlschema.to_json(**kwargs) self.assertIsInstance(col_json, str) self.assertEqual(len(col_json), 688) self.assertTrue(col_json.startswith('{"@xmlns:')) self.assertEqual(col_json[-1], '}') self.assertEqual( col_json, xmlschema.to_json(lazy=True, **kwargs) ) json_data = xmlschema.to_json(path='object', **kwargs) self.assertIn(json_data, col_json) self.assertEqual( json_data, xmlschema.to_json(path='object', lazy=True, **kwargs) ) self.assertEqual( json_data, xmlschema.to_json(validation='skip', path='object', lazy=True, **kwargs) ) json_data = xmlschema.to_json(path='object/author', **kwargs) self.assertIsInstance(json_data, str) self.assertEqual(len(json_data), 259) self.assertEqual(json_data[:4], '[{"@') self.assertEqual(json_data[-1], ']') self.assertEqual( json_data, xmlschema.to_json(path='object/author', lazy=True, **kwargs) ) self.assertEqual(json_data, xmlschema.to_json( validation='skip', path='object/author', lazy=True, **kwargs )) # Tests for issue #159 self.assertEqual(json_data, xmlschema.to_json( path='/col:collection/object/author', lazy=True, **kwargs )) self.assertEqual(json_data, xmlschema.to_json( validation='skip', path='/col:collection/object/author', lazy=True, **kwargs )) def test_path(self): xt = ElementTree.parse(self.vh_xml_file) xd = self.vh_schema.to_dict(xt, '/vh:vehicles/vh:cars', namespaces=self.vh_namespaces) self.assertEqual(xd['vh:car'], VEHICLES_DICT['vh:cars']['vh:car']) xd = self.vh_schema.to_dict(xt, '/vh:vehicles/vh:bikes', namespaces=self.vh_namespaces) self.assertEqual(xd['vh:bike'], VEHICLES_DICT['vh:bikes']['vh:bike']) def test_max_depth_argument(self): schema = self.schema_class(self.col_xsd_file) self.assertEqual( schema.decode(self.col_xml_file, max_depth=1), {'@xmlns:col': 'http://example.com/ns/collection', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd'}) xmlschema.limits.MAX_XML_DEPTH = 1 with self.assertRaises(XMLSchemaValidationError): schema.decode(self.col_xml_file) xmlschema.limits.MAX_XML_DEPTH = 9999 self.assertEqual( schema.decode(self.col_xml_file, max_depth=2), {'@xmlns:col': 'http://example.com/ns/collection', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://example.com/ns/collection collection.xsd', 'object': [{'@id': 'b0836217462', '@available': True}, {'@id': 'b0836217463', '@available': True}]}) def test_value_hook_argument(self): schema = self.schema_class(self.col_xsd_file) def ascii_strings(value, xsd_type): try: if not isinstance(value, str) or \ xsd_type.primitive_type.name != XSD_STRING: return value except AttributeError: return value else: return value.encode('utf-8') obj = schema.decode(self.col_xml_file, value_hook=ascii_strings) self.assertNotEqual(obj, schema.decode(self.col_xml_file)) root = schema.encode(obj) self.assertIsNone(etree_elements_assert_equal( root, ElementTree.parse(self.col_xml_file).getroot(), strict=False )) self.assertEqual(obj['object'][0]['title'], b'The Umbrellas') def test_non_global_schema_path(self): # Issue #157 xs = self.schema_class("""<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:foo="http://example.com/foo" targetNamespace="http://example.com/foo"> <xs:complexType name="type1"> <xs:sequence> <xs:element name="sub_part1" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:complexType name="type2"> <xs:sequence> <xs:element name="sub_part2" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:element name="part1" type="foo:type1" /> <xs:element name="part2" type="foo:type2" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") self.assertEqual( xs.to_dict( """<part1 xmlns:foo="http://example.com/foo"> <sub_part1>test</sub_part1> </part1>""", schema_path='.//part1', ), {"sub_part1": "test"} ) def test_validation_strict(self): self.assertRaises( xmlschema.XMLSchemaValidationError, self.vh_schema.to_dict, ElementTree.parse(self.casepath('examples/vehicles/vehicles-2_errors.xml')), validation='strict', namespaces=self.vh_namespaces ) def test_validation_skip(self): xt = ElementTree.parse(self.casepath('features/decoder/data3.xml')) xd = self.st_schema.decode(xt, validation='skip', namespaces={'ns': 'ns'}) self.assertEqual(xd['decimal_value'], ['abc']) def test_datatypes(self): xt = ElementTree.parse(self.casepath('features/decoder/data.xml')) xd = self.st_schema.to_dict(xt, namespaces=self.default_namespaces) self.assertEqual(xd, DATA_DICT) def test_datetime_types(self): xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>') self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>'), '2019-01-01T13:40:00') self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True), datatypes.DateTime10.fromstring('2019-01-01T13:40:00')) xs = self.get_schema('<xs:element name="dt" type="xs:date"/>') self.assertEqual(xs.decode('<dt>2001-04-15</dt>'), '2001-04-15') self.assertEqual(xs.decode('<dt>2001-04-15</dt>', datetime_types=True), datatypes.Date10.fromstring('2001-04-15')) xs = self.get_schema('<xs:attribute name="dt" type="xs:date"/>') self.assertEqual(xs.attributes['dt'].decode('2001-04-15'), '2001-04-15') self.assertEqual(xs.attributes['dt'].decode('2001-04-15', datetime_types=True), datatypes.Date10.fromstring('2001-04-15')) def test_duration_type(self): xs = self.get_schema('<xs:element name="td" type="xs:duration"/>') self.assertEqual(xs.decode('<td>P5Y3MT60H30.001S</td>'), 'P5Y3MT60H30.001S') self.assertEqual(xs.decode('<td>P5Y3MT60H30.001S</td>', datetime_types=True), datatypes.Duration.fromstring('P5Y3M2DT12H30.001S')) def test_default_converter(self): self.assertEqual(self.col_schema.to_dict(self.col_xml_file), COLLECTION_DICT) default_dict = self.col_schema.to_dict(self.col_xml_file, converter=xmlschema.XMLSchemaConverter) self.assertEqual(default_dict, COLLECTION_DICT) default_dict_root = self.col_schema.to_dict(self.col_xml_file, preserve_root=True) self.assertEqual(default_dict_root, {'col:collection': COLLECTION_DICT}) def test_visitor_converter(self): visitor_dict = self.col_schema.to_dict(self.col_xml_file, converter=UnorderedConverter) self.assertEqual(visitor_dict, COLLECTION_DICT) visitor_dict_root = self.col_schema.to_dict( self.col_xml_file, converter=UnorderedConverter(preserve_root=True)) self.assertEqual(visitor_dict_root, {'col:collection': COLLECTION_DICT}) def test_parker_converter(self): parker_dict = self.col_schema.to_dict(self.col_xml_file, converter=xmlschema.ParkerConverter) self.assertEqual(parker_dict, COLLECTION_PARKER) parker_dict_root = self.col_schema.to_dict( self.col_xml_file, converter=ParkerConverter(preserve_root=True), decimal_type=float) self.assertEqual(parker_dict_root, COLLECTION_PARKER_ROOT) def test_badgerfish_converter(self): badgerfish_dict = self.col_schema.to_dict( self.col_xml_file, converter=BadgerFishConverter, decimal_type=float) self.assertEqual(badgerfish_dict, COLLECTION_BADGERFISH) def test_abdera_converter(self): abdera_dict = self.col_schema.to_dict( self.col_xml_file, converter=AbderaConverter, decimal_type=float, dict_class=dict) self.assertEqual(abdera_dict, COLLECTION_ABDERA) def test_json_ml_converter(self): json_ml_dict = self.col_schema.to_dict(self.col_xml_file, converter=JsonMLConverter) self.assertEqual(json_ml_dict, COLLECTION_JSON_ML) def test_columnar_converter(self): columnar_dict = self.col_schema.to_dict(self.col_xml_file, converter=ColumnarConverter) self.assertEqual(columnar_dict, COLLECTION_COLUMNAR) columnar_dict = self.col_schema.to_dict( self.col_xml_file, converter=ColumnarConverter, attr_prefix='_', ) self.assertEqual(columnar_dict, COLLECTION_COLUMNAR_) with self.assertRaises(ValueError) as ctx: self.col_schema.to_dict( self.col_xml_file, converter=ColumnarConverter, attr_prefix='-', ) self.assertEqual(str(ctx.exception), "attr_prefix can be the empty string or a single/double underscore") def test_dict_granularity(self): """Based on Issue #22, test to make sure an xsd indicating list with dictionaries, returns just that even when it has a single dict. """ xsd_string = self.casepath('issues/issue_022/xsd_string.xsd') xml_string_1 = self.casepath('issues/issue_022/xml_string_1.xml') xml_string_2 = self.casepath('issues/issue_022/xml_string_2.xml') xsd_schema = self.schema_class(xsd_string) xml_data_1 = xsd_schema.to_dict(xml_string_1) xml_data_2 = xsd_schema.to_dict(xml_string_2) self.assertTrue(isinstance(xml_data_1['bar'], type(xml_data_2['bar'])), msg="XSD with an array that return a single element from " "xml must still yield a list.") def test_any_type_decoding(self): any_type = self.schema_class.meta_schema.types['anyType'] xml_data_1 = ElementTree.Element('dummy') self.assertIsNone(any_type.decode(xml_data_1)) xml_data_2 = ElementTree.fromstring('<root>\n <child_1/>\n <child_2/>\n</root>') # Fix for processContents='lax' (issue 273, previously result was None) self.assertEqual(any_type.decode(xml_data_2), {'child_1': [None], 'child_2': [None]}) def test_skip_wildcard_decoding(self): schema = self.schema_class("""<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:any processContents="skip"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") self.assertIsNone(schema.decode('<foo><bar/></foo>')) obj = schema.decode('<foo><bar/></foo>', process_skipped=True) self.assertEqual(obj, {'bar': None}) root = schema.encode(obj) self.assertEqual(root.tag, 'foo') self.assertEqual(len(root), 0) root = schema.encode(obj, process_skipped=True) self.assertEqual(root.tag, 'foo') self.assertEqual(len(root), 1) self.assertEqual(root[0].tag, 'bar') def test_any_type_decoding__issue_273(self): schema = self.schema_class(self.casepath('issues/issue_273/issue_273.xsd')) data = schema.to_dict(self.casepath('issues/issue_273/issue_273.xml')) self.assertDictEqual(data, { '@x': 'QA01_sequence', '@y': 2500, 'QA01': [ {'qa01_elem01': ['13'], 'qa01_elem02': ['5139'], 'qa01_elem03': ['170'], 'qa01_elem04': [{'@these': 'attributes', '@get': 'dropped', '$': '0'}], 'qa01_elem05': ['56'], 'qa01_elem06': ['11141178'] }]}) def test_choice_model_decoding__issue_041(self): schema = self.schema_class(self.casepath('issues/issue_041/issue_041.xsd')) data = schema.to_dict(self.casepath('issues/issue_041/issue_041.xml')) self.assertEqual(data, { '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:noNamespaceSchemaLocation': 'issue_041.xsd', 'Name': 'SomeNameValueThingy', 'Value': {'Integer': 0} }) def test_cdata_decoding(self): schema = self.schema_class(self.casepath('issues/issue_046/issue_046.xsd')) xml_file = self.casepath('issues/issue_046/issue_046.xml') self.assertEqual( schema.decode(xml_file, cdata_prefix='#'), dict( [('@xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'), ('@xsi:noNamespaceSchemaLocation', 'issue_046.xsd'), ('#1', 'Dear Mr.'), ('name', 'John Smith'), ('#2', '.\n Your order'), ('orderid', 1032), ('#3', 'will be shipped on'), ('shipdate', '2001-07-13'), ('#4', '.')] )) def test_string_facets(self): none_empty_string_type = self.st_schema.types['none_empty_string'] self.check_decode(none_empty_string_type, '', XMLSchemaValidationError) name_type = self.st_schema.types['NameType'] self.check_decode(name_type, '', XMLSchemaValidationError) def test_hex_binary_type(self): hex_code_type = self.st_schema.types['hexCode'] self.check_decode(hex_code_type, '00D7310A', datatypes.HexBinary(b'00D7310A')) self.check_decode(hex_code_type, 'D7310A', XMLSchemaValidationError) xs = self.get_schema('<xs:element name="hex" type="xs:hexBinary"/>') obj = xs.decode('<hex> 9AFD </hex>') self.assertEqual(obj, '9AFD') # Value string is collapsed anyway self.assertIsInstance(obj, str) obj = xs.decode('<hex> 9AFD </hex>', binary_types=True) self.assertEqual(obj, '9AFD') self.assertIsInstance(obj, datatypes.HexBinary) xs = self.get_schema('<xs:attribute name="hex" type="xs:hexBinary"/>') obj = xs.attributes['hex'].decode(' 9AFD ') self.assertEqual(obj, '9AFD') self.assertIsInstance(obj, str) obj = xs.attributes['hex'].decode(' 9AFD ', binary_types=True) self.assertEqual(obj, '9AFD') self.assertIsInstance(obj, datatypes.HexBinary) def test_base64_binary_type(self): base64_code_type = self.st_schema.types['base64Code'] self.check_decode(base64_code_type, base64.b64encode(b'ok'), XMLSchemaValidationError) base64_value = base64.b64encode(b'hello') expected_value = datatypes.Base64Binary(base64_value) self.check_decode(base64_code_type, base64_value, expected_value) # Attribute xs = self.get_schema('<xs:attribute name="b64" type="xs:base64Binary"/>') obj = xs.attributes['b64'].decode(base64_value.decode()) self.assertEqual(obj, expected_value) self.assertIsInstance(obj, str) obj = xs.attributes['b64'].decode(base64_value.decode(), binary_types=True) self.assertEqual(obj, expected_value) self.assertIsInstance(obj, datatypes.Base64Binary) # Element xs = self.get_schema('<xs:element name="b64" type="xs:base64Binary"/>') obj = xs.decode('<b64>{}</b64>'.format(base64_value.decode())) self.assertEqual(obj, expected_value) self.assertIsInstance(obj, str) obj = xs.decode('<b64>{}</b64>'.format(base64_value.decode()), binary_types=True) self.assertEqual(obj, expected_value) self.assertIsInstance(obj, datatypes.Base64Binary) self.check_decode(base64_code_type, base64.b64encode(b'abcefgh'), datatypes.Base64Binary('YWJjZWZnaA==')) self.check_decode(base64_code_type, b' Y W J j ZWZ\t\tn\na A= =', datatypes.Base64Binary('Y W J j ZWZ n a A= =')) self.check_decode(base64_code_type, u' Y W J j ZWZ\t\tn\na A= =', datatypes.Base64Binary('Y W J j ZWZ n a A= =')) self.check_decode(base64_code_type, base64.b64encode(b'abcefghi'), datatypes.Base64Binary('YWJjZWZnaGk=')) self.check_decode(base64_code_type, u'YWJjZWZnaA=', XMLSchemaValidationError) self.check_decode(base64_code_type, u'YWJjZWZna$==', XMLSchemaValidationError) base64_length4_type = self.st_schema.types['base64Length4'] self.check_decode(base64_length4_type, base64.b64encode(b'abc'), XMLSchemaValidationError) self.check_decode(base64_length4_type, base64.b64encode(b'abce'), datatypes.Base64Binary('YWJjZQ==')) self.check_decode(base64_length4_type, base64.b64encode(b'abcef'), XMLSchemaValidationError) base64_length5_type = self.st_schema.types['base64Length5'] self.check_decode(base64_length5_type, base64.b64encode(b'1234'), XMLSchemaValidationError) self.check_decode(base64_length5_type, base64.b64encode(b'12345'), datatypes.Base64Binary('MTIzNDU=')) self.check_decode(base64_length5_type, base64.b64encode(b'123456'), XMLSchemaValidationError) def test_decimal_type(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:simpleType name="A_type"> <xs:restriction base="xs:decimal"> <xs:minInclusive value="100.50"/> </xs:restriction> </xs:simpleType> """) self.check_decode(schema, '<A>120.48</A>', Decimal('120.48')) self.check_decode(schema, '<A>100.50</A>', Decimal('100.50'), process_namespaces=False) self.check_decode(schema, '<A>100.49</A>', XMLSchemaValidationError) self.check_decode(schema, '<A>120.48</A>', 120.48, decimal_type=float) # Issue #66 self.check_decode(schema, '<A>120.48</A>', '120.48', decimal_type=str) def test_nillable__issue_076(self): xsd_string = """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="foo" type="Foo" /> <xs:complexType name="Foo"> <xs:sequence minOccurs="1" maxOccurs="1"> <xs:element name="bar" type="xs:integer" nillable="true" /> </xs:sequence> </xs:complexType> </xs:schema> """ xsd_schema = self.schema_class(xsd_string) xml_string_1 = "<foo><bar>0</bar></foo>" xml_string_2 = """<?xml version="1.0" encoding="UTF-8"?> <foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <bar xsi:nil="true"></bar> </foo> """ self.assertTrue(xsd_schema.is_valid(source=xml_string_1, use_defaults=False)) self.assertTrue(xsd_schema.is_valid(source=xml_string_2, use_defaults=False)) obj = xsd_schema.decode(xml_string_2, use_defaults=False) self.check_etree_elements(ElementTree.fromstring(xml_string_2), xsd_schema.encode(obj)) def test_default_namespace__issue_077(self): xs = self.schema_class("""<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example.com/foo"> <xs:element name="foo" type="xs:string" /> </xs:schema>""") self.assertEqual(xs.to_dict("""<foo xmlns="http://example.com/foo">bar</foo>""", path='/foo', namespaces={'': 'http://example.com/foo'}), 'bar') self.assertEqual(xs.to_dict("""<foo>bar</foo>""", path='/foo', namespaces={'': 'http://example.com/foo'}), None) def test_complex_with_simple_content_restriction(self): xs = self.schema_class( self.casepath('features/derivations/complex-with-simple-content-restriction.xsd') ) self.assertTrue(xs.is_valid('<value>10</value>')) self.assertFalse(xs.is_valid('<value>alpha</value>')) self.assertEqual(xs.decode('<value>10</value>'), 10) def test_union_types__issue_103(self): decimal_or_nan = self.st_schema.types['myType'] self.check_decode(decimal_or_nan, '95.0', Decimal('95.0')) self.check_decode(decimal_or_nan, 'NaN', u'NaN') def test_default_values__issue_108(self): # From issue #108 xsd_text = """<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="root" default="default_value"/> <xs:complexType name="root"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="attr" type="xs:string"/> <xs:attribute name="attrWithDefault" type="xs:string" default="default_value"/> <xs:attribute name="attrWithFixed" type="xs:string" fixed="fixed_value"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="simple_root" type="xs:string" default="default_value"/> </xs:schema>""" schema = self.schema_class(xsd_text) self.assertEqual(schema.to_dict("<root>text</root>"), {'@attrWithDefault': 'default_value', '@attrWithFixed': 'fixed_value', '$': 'text'}) self.assertEqual(schema.to_dict("<root/>"), {'@attrWithDefault': 'default_value', '@attrWithFixed': 'fixed_value', '$': 'default_value'}) self.assertEqual(schema.to_dict("""<root attr="attr_value">text</root>"""), {'$': 'text', '@attr': 'attr_value', '@attrWithDefault': 'default_value', '@attrWithFixed': 'fixed_value'}) self.assertEqual(schema.to_dict("<root>text</root>", use_defaults=False), {'@attrWithFixed': 'fixed_value', '$': 'text'}) self.assertEqual(schema.to_dict("""<root attr="attr_value">text</root>""", use_defaults=False), {'$': 'text', '@attr': 'attr_value', '@attrWithFixed': 'fixed_value'}) self.assertEqual(schema.to_dict("<root/>", use_defaults=False), {'@attrWithFixed': 'fixed_value'}) self.assertEqual(schema.to_dict("<simple_root/>"), 'default_value') self.assertIsNone(schema.to_dict("<simple_root/>", use_defaults=False)) def test_decoding_errors_with_validation_modes(self): schema = self.schema_class("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="rootType" /> <xs:complexType name="rootType"> <xs:simpleContent> <xs:extension base="xs:int"> <xs:attribute name="int_attr" type="xs:int"/> <xs:attribute name="bool_attr" type="xs:boolean"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="simple_root" type="xs:float"/> </xs:schema>""") self.assertIsNone(schema.to_dict("<simple_root>alpha</simple_root>", validation='lax')[0]) self.assertEqual(schema.to_dict("<root int_attr='10'>20</root>"), {'@int_attr': 10, '$': 20}) self.assertEqual(schema.to_dict("<root int_attr='wrong'>20</root>", validation='lax')[0], {'@int_attr': None, '$': 20}) self.assertEqual(schema.to_dict("<root int_attr='wrong'>20</root>", validation='skip'), {'@int_attr': 'wrong', '$': 20}) def test_keep_unknown_tags__issue_204(self): schema = self.schema_class(self.casepath('issues/issue_204/issue_204.xsd')) self.assertTrue(schema.is_valid(self.casepath('issues/issue_204/issue_204_1.xml'))) self.assertFalse(schema.is_valid(self.casepath('issues/issue_204/issue_204_2.xml'))) data = schema.decode(self.casepath('issues/issue_204/issue_204_2.xml'), validation='lax') self.assertEqual(set(x for x in data[0] if x[0] != '@'), {'child2', 'child5'}) data = schema.decode(self.casepath('issues/issue_204/issue_204_3.xml'), validation='lax') self.assertEqual(set(x for x in data[0] if x[0] != '@'), {'child2', 'child5'}) data = schema.decode(self.casepath('issues/issue_204/issue_204_3.xml'), validation='lax', keep_unknown=True) self.assertEqual(set(x for x in data[0] if x[0] != '@'), {'child2', 'unknown', 'child5'}) self.assertEqual(data[0]['unknown'], {'a': ['1'], 'b': [None]}) data = schema.decode(self.casepath('issues/issue_204/issue_204_2.xml'), validation='skip') self.assertEqual(set(x for x in data if x[0] != '@'), {'child2', 'child5'}) data = schema.decode(self.casepath('issues/issue_204/issue_204_3.xml'), validation='skip', keep_unknown=True) self.assertEqual(set(x for x in data if x[0] != '@'), {'child2', 'unknown', 'child5'}) self.assertEqual(data['unknown'], {'a': ['1'], 'b': [None]}) def test_error_message__issue_115(self): schema = self.schema_class(self.casepath('issues/issue_115/Rotation.xsd')) rotation_data = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" ' \ 'pitch="0.0" roll="0.0" yaw="-1.0" />' message_lines = [] try: schema.decode(rotation_data) except Exception as err: message_lines = str(err).split('\n') self.assertTrue(message_lines, msg="Empty error message!") self.assertEqual(message_lines[-6], 'Instance:') self.assertEqual(message_lines[-4].strip(), rotation_data) self.assertEqual(message_lines[-2], 'Path: /tns:rotation') def test_empty_base_type_extension_single_value(self): xsd_text = """<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > <xs:element name="root" type="rootType" /> <xs:complexType name="BaseType" abstract="true"> <xs:sequence /> </xs:complexType> <xs:complexType name="ExtensionType"> <xs:complexContent> <xs:extension base="BaseType"> <xs:sequence> <xs:element name="Content" type="xs:string" /> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="rootType"> <xs:sequence> <xs:element name="ExtensionSub" type="BaseType" /> </xs:sequence> </xs:complexType> </xs:schema>""" schema = self.schema_class(xsd_text) xml_source = """<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ExtensionSub xsi:type="ExtensionType"> <Content>my content</Content> </ExtensionSub> </root>""" result = schema.to_dict(xml_source) expected = { "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", "ExtensionSub": { "@xsi:type": "ExtensionType", "Content": "my content", } } self.assertEqual(result, expected) root = schema.to_etree(result) self.assertIsNone(etree_elements_assert_equal( root, ElementTree.XML(xml_source), strict=False )) def test_issue_190(self): # Changed is_single() for XsdElement to check also parent group. schema = self.schema_class(self.casepath('issues/issue_190/issue_190.xsd')) self.assertEqual( schema.to_dict(self.casepath('issues/issue_190/issue_190.xml')), {'a': {'c': ['1']}, 'b': {'c': ['1'], 'e': ['1']}} ) def test_issue_200(self): # Schema path is required when path doesn't resolve to an XSD element schema = self.schema_class(self.casepath('issues/issue_200/issue_200.xsd')) self.assertEqual( schema.to_dict(self.casepath('issues/issue_200/issue_200.xml'), path='/na:main/na:item[@doc_id=1]'), {'@doc_id': 1, '@ref_id': 'k1', '$': 'content_k1'} ) with self.assertRaises(XMLSchemaValidationError) as ctx: schema.to_dict(self.casepath('issues/issue_200/issue_200.xml'), path='/na:main/na:item[@doc_id=2]'), self.assertIn('is not an element of the schema', str(ctx.exception)) def test_issue_238__decode_bytes_strings(self): with open(self.vh_xml_file, 'rb') as fp: vh_xml_data = fp.read() self.assertIsInstance(vh_xml_data, bytes) obj = self.vh_schema.decode(vh_xml_data) # ElementTree accepts also bytes but emits Unicode strings only for value in iter_nested_iterables(obj): self.assertNotIsInstance(value, bytes) def test_issue_240__decode_unicode_to_json(self): schema = self.get_schema('<xs:element name="chars" type="xs:string"/>') xml_data = '<chars>øæå</chars>' obj = xmlschema.to_dict(xml_data, schema=schema, decimal_type=str) self.assertEqual(obj, 'øæå') self.assertEqual(obj, schema.decode(xml_data, decimal_type=str)) json_data = json.dumps(obj, indent=4) self.assertEqual(obj, 'øæå') self.assertIsInstance(obj, str) self.assertEqual(json_data.encode("utf-8"), b'"\\u00f8\\u00e6\\u00e5"') class TestDecoding11(TestDecoding): schema_class = XMLSchema11 def test_datetime_types(self): xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>') self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>'), '2019-01-01T13:40:00') self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True), datatypes.DateTime.fromstring('2019-01-01T13:40:00')) xs = self.get_schema('<xs:element name="dt" type="xs:date"/>') self.assertEqual(xs.decode('<dt>2001-04-15</dt>'), '2001-04-15') self.assertEqual(xs.decode('<dt>2001-04-15</dt>', datetime_types=True), datatypes.Date.fromstring('2001-04-15')) xs = self.get_schema('<xs:attribute name="dt" type="xs:date"/>') self.assertEqual(xs.attributes['dt'].decode('2001-04-15'), '2001-04-15') self.assertEqual(xs.attributes['dt'].decode('2001-04-15', datetime_types=True), datatypes.Date.fromstring('2001-04-15')) def test_derived_duration_types(self): xs = self.get_schema('<xs:element name="td" type="xs:yearMonthDuration"/>') self.assertEqual(xs.decode('<td>P0Y4M</td>'), 'P0Y4M') self.assertEqual(xs.decode('<td>P2Y10M</td>', datetime_types=True), datatypes.Duration.fromstring('P2Y10M')) xs = self.get_schema('<xs:element name="td" type="xs:dayTimeDuration"/>') self.assertEqual(xs.decode('<td>P2DT6H30M30.001S</td>'), 'P2DT6H30M30.001S') self.assertEqual(xs.decode('<td>P2DT26H</td>'), 'P2DT26H') self.assertEqual(xs.decode('<td>P2DT6H30M30.001S</td>', datetime_types=True), datatypes.Duration.fromstring('P2DT6H30M30.001S')) def test_type_alternatives(self): xs = self.schema_class(self.casepath('features/elements/type_alternatives-no-ns.xsd')) self.assertTrue(xs.is_valid('<value choice="int">10</value>')) self.assertFalse(xs.is_valid('<value choice="int">10.1</value>')) self.assertTrue(xs.is_valid('<value choice="float">10.1</value>')) self.assertFalse(xs.is_valid('<value choice="float">alpha</value>')) self.assertFalse(xs.is_valid('<value choice="bool">alpha</value>')) self.assertTrue(xs.is_valid('<value choice="bool">0</value>')) self.assertTrue(xs.is_valid('<value choice="bool">true</value>')) xs = self.schema_class(self.casepath('features/elements/type_alternatives.xsd')) self.assertTrue(xs.is_valid('<ns:value xmlns:ns="ns" choice="int">10</ns:value>')) self.assertFalse(xs.is_valid('<ns:value xmlns:ns="ns" choice="int">10.1</ns:value>')) self.assertTrue(xs.is_valid('<ns:value xmlns:ns="ns" choice="float">10.1</ns:value>')) self.assertFalse(xs.is_valid('<ns:value xmlns:ns="ns" choice="float">alpha</ns:value>')) self.assertFalse(xs.is_valid('<ns:value xmlns:ns="ns" choice="bool">alpha</ns:value>')) self.assertTrue(xs.is_valid('<ns:value xmlns:ns="ns" choice="bool">0</ns:value>')) self.assertTrue(xs.is_valid('<ns:value xmlns:ns="ns" choice="bool">true</ns:value>')) if __name__ == '__main__': import platform header_template = "Test xmlschema decoding with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validation/test_encoding.py��������������������������������������������������0000664�0000000�0000000�00000075245�14211403446�0022261�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import sys import os import unittest from textwrap import dedent try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from elementpath import datatypes from xmlschema import XMLSchemaEncodeError, XMLSchemaValidationError from xmlschema.converters import UnorderedConverter from xmlschema.etree import etree_element, etree_tostring, ElementTree from xmlschema.helpers import local_name, is_etree_element from xmlschema.resources import XMLResource from xmlschema.validators.exceptions import XMLSchemaChildrenValidationError from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase class TestEncoding(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') def check_encode(self, xsd_component, data, expected, **kwargs): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, xsd_component.encode, data, **kwargs) elif is_etree_element(expected): elem = xsd_component.encode(data, **kwargs) self.check_etree_elements(expected, elem) else: obj = xsd_component.encode(data, **kwargs) if isinstance(obj, tuple) and len(obj) == 2 and isinstance(obj[1], list): self.assertEqual(expected, obj[0]) self.assertTrue(isinstance(obj[0], type(expected))) elif is_etree_element(obj): namespaces = kwargs.pop('namespaces', self.default_namespaces) self.assertEqual(expected, etree_tostring(obj, namespaces=namespaces).strip()) else: self.assertEqual(expected, obj) self.assertTrue(isinstance(obj, type(expected))) def test_decode_encode(self): """Test encode after a decode, checking the re-encoded tree.""" filename = self.casepath('examples/collection/collection.xml') xt = ElementTree.parse(filename) xd = self.col_schema.to_dict(filename) elem = self.col_schema.encode(xd, path='./col:collection', namespaces=self.col_namespaces) self.assertEqual( len([e for e in elem.iter()]), 20, msg="The encoded tree must have 20 elements as the origin." ) self.assertTrue(all( local_name(e1.tag) == local_name(e2.tag) for e1, e2 in zip(elem.iter(), xt.getroot().iter()) )) def test_string_based_builtin_types(self): self.check_encode(self.xsd_types['string'], 'sample string ', u'sample string ') self.check_encode(self.xsd_types['normalizedString'], ' sample string ', u' sample string ') self.check_encode(self.xsd_types['normalizedString'], '\n\r sample\tstring\n', u' sample string ') self.check_encode(self.xsd_types['token'], '\n\r sample\t\tstring\n ', u'sample string') self.check_encode(self.xsd_types['language'], 'sample string', XMLSchemaValidationError) self.check_encode(self.xsd_types['language'], ' en ', u'en') self.check_encode(self.xsd_types['Name'], 'first_name', u'first_name') self.check_encode(self.xsd_types['Name'], ' first_name ', u'first_name') self.check_encode(self.xsd_types['Name'], 'first name', XMLSchemaValidationError) self.check_encode(self.xsd_types['Name'], '1st_name', XMLSchemaValidationError) self.check_encode(self.xsd_types['Name'], 'first_name1', u'first_name1') self.check_encode(self.xsd_types['Name'], 'first:name', u'first:name') self.check_encode(self.xsd_types['NCName'], 'first_name', u'first_name') self.check_encode(self.xsd_types['NCName'], 'first:name', XMLSchemaValidationError) self.check_encode(self.xsd_types['ENTITY'], 'first:name', XMLSchemaValidationError) self.check_encode(self.xsd_types['ID'], 'first:name', XMLSchemaValidationError) self.check_encode(self.xsd_types['IDREF'], 'first:name', XMLSchemaValidationError) def test_decimal_based_builtin_types(self): self.check_encode(self.xsd_types['decimal'], -99.09, u'-99.09') self.check_encode(self.xsd_types['decimal'], '-99.09', u'-99.09') self.check_encode(self.xsd_types['integer'], 1000, u'1000') self.check_encode(self.xsd_types['integer'], 100.0, XMLSchemaEncodeError) self.check_encode(self.xsd_types['integer'], 100.0, u'100', validation='lax') self.check_encode(self.xsd_types['short'], 1999, u'1999') self.check_encode(self.xsd_types['short'], 10000000, XMLSchemaValidationError) self.check_encode(self.xsd_types['float'], 100.0, u'100.0') self.check_encode(self.xsd_types['float'], 'hello', XMLSchemaEncodeError) self.check_encode(self.xsd_types['double'], -4531.7, u'-4531.7') self.check_encode(self.xsd_types['positiveInteger'], -1, XMLSchemaValidationError) self.check_encode(self.xsd_types['positiveInteger'], 0, XMLSchemaValidationError) self.check_encode(self.xsd_types['nonNegativeInteger'], 0, u'0') self.check_encode(self.xsd_types['nonNegativeInteger'], -1, XMLSchemaValidationError) self.check_encode(self.xsd_types['negativeInteger'], -100, u'-100') self.check_encode(self.xsd_types['nonPositiveInteger'], 7, XMLSchemaValidationError) self.check_encode(self.xsd_types['unsignedLong'], 101, u'101') self.check_encode(self.xsd_types['unsignedLong'], -101, XMLSchemaValidationError) self.check_encode(self.xsd_types['nonPositiveInteger'], 7, XMLSchemaValidationError) def test_list_builtin_types(self): self.check_encode(self.xsd_types['IDREFS'], ['first_name'], u'first_name') self.check_encode(self.xsd_types['IDREFS'], 'first_name', u'first_name') # Transform data to list self.check_encode(self.xsd_types['IDREFS'], ['one', 'two', 'three'], u'one two three') self.check_encode(self.xsd_types['IDREFS'], [1, 'two', 'three'], XMLSchemaValidationError) self.check_encode(self.xsd_types['NMTOKENS'], ['one', 'two', 'three'], u'one two three') self.check_encode(self.xsd_types['ENTITIES'], ('mouse', 'cat', 'dog'), u'mouse cat dog') def test_datetime_builtin_type(self): xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>') dt = xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True) self.assertIsInstance(dt, datatypes.DateTime10) self.assertEqual(etree_tostring(xs.encode(dt)), '<dt>2019-01-01T13:40:00</dt>') dt = xs.decode('<dt>2019-01-01T13:40:00</dt>') self.assertIsInstance(dt, str) self.assertEqual(etree_tostring(xs.encode(dt)), '<dt>2019-01-01T13:40:00</dt>') def test_date_builtin_type(self): xs = self.get_schema('<xs:element name="dt" type="xs:date"/>') date = xs.decode('<dt>2001-04-15</dt>', datetime_types=True) self.assertEqual(etree_tostring(xs.encode(date)), '<dt>2001-04-15</dt>') mdate_type = self.st_schema.types['mdate'] date = mdate_type.encode('2001-01-01') self.assertIsInstance(date, str) self.assertEqual(date, '2001-01-01') date = mdate_type.encode(datatypes.Date.fromstring('2001-01-01')) self.assertIsInstance(date, str) self.assertEqual(date, '2001-01-01') def test_duration_builtin_type(self): xs = self.get_schema('<xs:element name="td" type="xs:duration"/>') duration = xs.decode('<td>P5Y3MT60H30.001S</td>', datetime_types=True) self.assertEqual(etree_tostring(xs.encode(duration)), '<td>P5Y3M2DT12H30.001S</td>') def test_gregorian_year_builtin_type(self): xs = self.get_schema('<xs:element name="td" type="xs:gYear"/>') gyear = xs.decode('<td>2000</td>', datetime_types=True) self.assertEqual(etree_tostring(xs.encode(gyear)), '<td>2000</td>') def test_gregorian_yearmonth_builtin_type(self): xs = self.get_schema('<xs:element name="td" type="xs:gYearMonth"/>') gyear_month = xs.decode('<td>2000-12</td>', datetime_types=True) self.assertEqual(etree_tostring(xs.encode(gyear_month)), '<td>2000-12</td>') def test_hex_binary_type(self): hex_code_type = self.st_schema.types['hexCode'] value = hex_code_type.encode('00D7310A') self.assertEqual(value, '00D7310A') self.assertIsInstance(value, str) value = hex_code_type.encode(datatypes.HexBinary(b'00D7310A')) self.assertEqual(value, '00D7310A') self.assertIsInstance(value, str) def test_base64_binary_type(self): base64_code_type = self.st_schema.types['base64Code'] value = base64_code_type.encode('YWJjZWZnaA==') self.assertEqual(value, 'YWJjZWZnaA==') self.assertIsInstance(value, str) value = base64_code_type.encode(datatypes.Base64Binary(b'YWJjZWZnaA==')) self.assertEqual(value, 'YWJjZWZnaA==') self.assertIsInstance(value, str) def test_list_types(self): list_of_strings = self.st_schema.types['list_of_strings'] self.check_encode(list_of_strings, (10, 25, 40), '10 25 40', validation='lax') self.check_encode(list_of_strings, (10, 25, 40), '10 25 40', validation='skip') self.check_encode(list_of_strings, ['a', 'b', 'c'], 'a b c', validation='skip') list_of_integers = self.st_schema.types['list_of_integers'] self.check_encode(list_of_integers, (10, 25, 40), '10 25 40') self.check_encode(list_of_integers, (10, 25.0, 40), XMLSchemaValidationError) self.check_encode(list_of_integers, (10, 25.0, 40), '10 25 40', validation='lax') list_of_floats = self.st_schema.types['list_of_floats'] self.check_encode(list_of_floats, [10.1, 25.0, 40.0], '10.1 25.0 40.0') self.check_encode(list_of_floats, [10.1, 25, 40.0], '10.1 25.0 40.0', validation='lax') self.check_encode(list_of_floats, [10.1, False, 40.0], '10.1 0.0 40.0', validation='lax') list_of_booleans = self.st_schema.types['list_of_booleans'] self.check_encode(list_of_booleans, [True, False, True], 'true false true') self.check_encode(list_of_booleans, [10, False, True], XMLSchemaEncodeError) self.check_encode(list_of_booleans, [True, False, 40.0], 'true false', validation='lax') self.check_encode(list_of_booleans, [True, False, 40.0], 'true false 40.0', validation='skip') def test_union_types(self): integer_or_float = self.st_schema.types['integer_or_float'] self.check_encode(integer_or_float, -95, u'-95') self.check_encode(integer_or_float, -95.0, u'-95.0') self.check_encode(integer_or_float, True, XMLSchemaEncodeError) self.check_encode(integer_or_float, True, u'1', validation='lax') integer_or_string = self.st_schema.types['integer_or_string'] self.check_encode(integer_or_string, 89, u'89') self.check_encode(integer_or_string, 89.0, u'89', validation='lax') self.check_encode(integer_or_string, 89.0, XMLSchemaEncodeError) self.check_encode(integer_or_string, False, XMLSchemaEncodeError) self.check_encode(integer_or_string, "Venice ", u'Venice ') boolean_or_integer_or_string = self.st_schema.types['boolean_or_integer_or_string'] self.check_encode(boolean_or_integer_or_string, 89, u'89') self.check_encode(boolean_or_integer_or_string, 89.0, u'89', validation='lax') self.check_encode(boolean_or_integer_or_string, 89.0, XMLSchemaEncodeError) self.check_encode(boolean_or_integer_or_string, False, u'false') self.check_encode(boolean_or_integer_or_string, "Venice ", u'Venice ') def test_simple_elements(self): elem = etree_element('A') elem.text = '89' self.check_encode(self.get_element('A', type='xs:string'), '89', elem) self.check_encode(self.get_element('A', type='xs:integer'), 89, elem) elem.text = '-10.4' self.check_encode(self.get_element('A', type='xs:float'), -10.4, elem) elem.text = 'false' self.check_encode(self.get_element('A', type='xs:boolean'), False, elem) elem.text = 'true' self.check_encode(self.get_element('A', type='xs:boolean'), True, elem) self.check_encode(self.get_element('A', type='xs:short'), 128000, XMLSchemaValidationError) elem.text = '0' self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), 0, elem) self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), '0', XMLSchemaValidationError) self.check_encode(self.get_element('A', type='xs:positiveInteger'), 0, XMLSchemaValidationError) elem.text = '-1' self.check_encode(self.get_element('A', type='xs:negativeInteger'), -1, elem) self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), -1, XMLSchemaValidationError) def test_complex_elements(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type" mixed="true"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="a1" type="xs:short" use="required"/> <xs:attribute name="a2" type="xs:negativeInteger"/> </xs:extension> </xs:simpleContent> </xs:complexType> """) self.check_encode( schema.elements['A'], data={'@a1': 10, '@a2': -1, '$': 'simple '}, expected='<A a1="10" a2="-1">simple </A>', ) self.check_encode( schema.elements['A'], {'@a1': 10, '@a2': -1, '$': 'simple '}, ElementTree.fromstring('<A a1="10" a2="-1">simple </A>'), ) self.check_encode( schema.elements['A'], {'@a1': 10, '@a2': -1}, ElementTree.fromstring('<A a1="10" a2="-1"/>') ) self.check_encode( schema.elements['A'], {'@a1': 10, '$': 'simple '}, ElementTree.fromstring('<A a1="10">simple </A>') ) self.check_encode(schema.elements['A'], {'@a2': -1, '$': 'simple '}, XMLSchemaValidationError) schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence> <xs:element name="B1" type="xs:string"/> <xs:element name="B2" type="xs:integer"/> <xs:element name="B3" type="xs:boolean"/> </xs:sequence> </xs:complexType> """) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('B3', False)]), expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\n<B3>false</B3>\n</A>', indent=0, ) self.check_encode(schema.elements['A'], {'B1': 'abc', 'B2': 10, 'B4': False}, XMLSchemaValidationError) def test_error_message(self): schema = self.schema_class(self.casepath('issues/issue_115/Rotation.xsd')) rotation_data = { "@roll": 0.0, "@pitch": 0.0, "@yaw": -1.0 # <----- invalid value, must be between 0 and 360 } message_lines = [] try: schema.encode(rotation_data) except XMLSchemaValidationError as err: message_lines = str(err).split('\n') self.assertIsNone(err.source) self.assertIsNone(err.path) self.assertTrue(message_lines, msg="Empty error message!") self.assertEqual(message_lines[-4], 'Instance:') if sys.version_info < (3, 8): text = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" ' \ 'pitch="0.0" roll="0.0" yaw="-1.0" />' else: text = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" ' \ 'roll="0.0" pitch="0.0" yaw="-1.0" />' self.assertEqual(message_lines[-2].strip(), text) # With 'lax' validation a dummy resource is assigned to source attribute _, errors = schema.encode(rotation_data, validation='lax') self.assertIsInstance(errors[0].source, XMLResource) self.assertEqual(errors[0].path, '/{http://www.example.org/Rotation/}rotation') def test_max_occurs_sequence(self): # Issue #119 schema = self.get_schema(""" <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:element name="A" type="xs:integer" maxOccurs="2" /> </xs:sequence> </xs:complexType> </xs:element>""") # Check validity self.assertIsNone(schema.validate("<foo><A>1</A></foo>")) self.assertIsNone(schema.validate("<foo><A>1</A><A>2</A></foo>")) with self.assertRaises(XMLSchemaChildrenValidationError): schema.validate("<foo><A>1</A><A>2</A><A>3</A></foo>") self.assertTrue(is_etree_element(schema.to_etree({'A': 1}, path='foo'))) self.assertTrue(is_etree_element(schema.to_etree({'A': [1]}, path='foo'))) self.assertTrue(is_etree_element(schema.to_etree({'A': [1, 2]}, path='foo'))) with self.assertRaises(XMLSchemaChildrenValidationError): schema.to_etree({'A': [1, 2, 3]}, path='foo') schema = self.get_schema(""" <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:element name="A" type="xs:integer" maxOccurs="2" /> <xs:element name="B" type="xs:integer" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element>""") self.assertTrue(is_etree_element(schema.to_etree({'A': [1, 2]}, path='foo'))) with self.assertRaises(XMLSchemaChildrenValidationError): schema.to_etree({'A': [1, 2, 3]}, path='foo') def test_encode_unordered_content(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type" mixed="true"> <xs:sequence> <xs:element name="B1" type="xs:string"/> <xs:element name="B2" type="xs:integer"/> <xs:element name="B3" type="xs:boolean"/> </xs:sequence> </xs:complexType> """) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B2', 10), ('B1', 'abc'), ('B3', True)]), expected=XMLSchemaChildrenValidationError ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B2', 10), ('B1', 'abc'), ('B3', True)]), expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\n<B3>true</B3>\n</A>', indent=0, cdata_prefix='#', converter=UnorderedConverter ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('#1', 'hello'), ('B3', True)]), expected='<A>\nhello<B1>abc</B1>\n<B2>10</B2>\n<B3>true</B3>\n</A>', indent=0, cdata_prefix='#', converter=UnorderedConverter ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('#1', 'hello'), ('B3', True)]), expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\nhello\n<B3>true</B3>\n</A>', indent=0, cdata_prefix='#' ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('#1', 'hello')]), expected=XMLSchemaValidationError, indent=0, cdata_prefix='#' ) def test_encode_unordered_content_2(self): """Here we test with a default converter at the schema level""" schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type" mixed="true"> <xs:sequence> <xs:element name="B1" type="xs:string"/> <xs:element name="B2" type="xs:integer"/> <xs:element name="B3" type="xs:boolean"/> </xs:sequence> </xs:complexType> """, converter=UnorderedConverter) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B2', 10), ('B1', 'abc'), ('B3', True)]), expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\n<B3>true</B3>\n</A>', indent=0, cdata_prefix='#' ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('#1', 'hello'), ('B3', True)]), expected=u'<A>\nhello<B1>abc</B1>\n<B2>10</B2>\n<B3>true</B3>\n</A>', indent=0, cdata_prefix='#' ) self.check_encode( xsd_component=schema.elements['A'], data=dict([('B1', 'abc'), ('B2', 10), ('#1', 'hello')]), expected=XMLSchemaValidationError, indent=0, cdata_prefix='#' ) def test_strict_trailing_content(self): """Too many elements for a group raises an exception.""" schema = self.get_schema(""" <xs:element name="foo"> <xs:complexType> <xs:sequence minOccurs="2" maxOccurs="2"> <xs:element name="A" minOccurs="0" type="xs:integer" nillable="true" /> </xs:sequence> </xs:complexType> </xs:element> """) self.check_encode( schema.elements['foo'], data={"A": [1, 2, 3]}, expected=XMLSchemaChildrenValidationError, ) def test_unordered_converter_repeated_sequence_of_elements(self): schema = self.get_schema(""" <xs:element name="foo"> <xs:complexType> <xs:sequence minOccurs="1" maxOccurs="2"> <xs:element name="A" minOccurs="0" type="xs:integer" nillable="true" /> <xs:element name="B" minOccurs="0" type="xs:integer" nillable="true" /> </xs:sequence> </xs:complexType> </xs:element> """) root = schema.to_etree(dict([('A', [1, 2]), ('B', [3, 4])])) self.assertListEqual([e.text for e in root], ['1', '3', '2', '4']) root = schema.to_etree({"A": [1, 2], "B": [3, 4]}, converter=UnorderedConverter) self.assertListEqual([e.text for e in root], ['1', '3', '2', '4']) root = schema.to_etree({"A": [1, 2], "B": [3, 4]}, unordered=True) self.assertListEqual([e.text for e in root], ['1', '3', '2', '4']) def test_xsi_type_and_attributes_unmap__issue_214(self): schema = self.schema_class("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xmlschema.test/ns" targetNamespace="http://xmlschema.test/ns"> <xs:element name="a" type="xs:string"/> <xs:complexType name="altType"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="a1" type="xs:string" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:schema>""") xml1 = """<a xmlns="http://xmlschema.test/ns">alpha</a>""" self.assertEqual(schema.decode(xml1), 'alpha') xml2 = """<a xmlns="http://xmlschema.test/ns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="altType" a1="beta">alpha</a>""" obj = schema.decode(xml2) self.assertEqual(obj, {'@xmlns': 'http://xmlschema.test/ns', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:type': 'altType', '@a1': 'beta', '$': 'alpha'}) root = schema.encode(obj, path='{http://xmlschema.test/ns}a') self.assertEqual(root.tag, '{http://xmlschema.test/ns}a') self.assertEqual(root.attrib, { '{http://www.w3.org/2001/XMLSchema-instance}type': 'altType', 'a1': 'beta' }) def test_element_encoding_with_defaults__issue_218(self): schema = self.schema_class(dedent("""\ <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="values" type="myType"/> <xs:complexType name="myType"> <xs:sequence> <xs:element name="b1" type="xs:boolean" default="1"/> <xs:element name="b2" type="xs:boolean" default="true"/> <xs:element name="b3" type="xs:boolean" default="false"/> </xs:sequence> </xs:complexType> </xs:schema>""")) self.assertEqual(schema.decode('<values><b1/><b2/><b3/></values>'), {'b1': True, 'b2': True, 'b3': False}) values = schema.encode({'b1': None, 'b2': True, 'b3': False}) self.assertEqual(len(values), 3) self.assertEqual(values[0].tag, 'b1') self.assertEqual(values[0].text, '1') self.assertEqual(values[1].tag, 'b2') self.assertEqual(values[1].text, 'true') self.assertEqual(values[2].tag, 'b3') self.assertEqual(values[2].text, 'false') values = schema.encode({'b1': False, 'b2': True, 'b3': None}) self.assertEqual(len(values), 3) self.assertEqual(values[0].tag, 'b1') self.assertEqual(values[0].text, 'false') self.assertEqual(values[1].tag, 'b2') self.assertEqual(values[1].text, 'true') self.assertEqual(values[2].tag, 'b3') self.assertEqual(values[2].text, 'false') def test_attribute_encoding_with_defaults__issue_218(self): schema = self.schema_class(dedent("""\ <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="values" type="myType"/> <xs:complexType name="myType"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="b1" type="xs:boolean" default="1"/> <xs:attribute name="b2" type="xs:boolean" default="true"/> <xs:attribute name="b3" type="xs:boolean" default="false"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:schema>""")) self.assertTrue(schema.is_valid('<values>content</values>')) self.assertEqual(schema.decode('<values/>'), {'@b1': True, '@b2': True, '@b3': False}) elem = schema.encode({}) self.assertIsNone(elem.text) self.assertEqual(elem.attrib, {'b1': '1', 'b2': 'true', 'b3': 'false'}) elem = schema.encode({'@b1': True, '@b3': True}) self.assertIsNone(elem.text) self.assertEqual(elem.attrib, {'b1': 'true', 'b2': 'true', 'b3': 'true'}) elem = schema.encode({'@b2': False, '@b1': False}) self.assertIsNone(elem.text) self.assertEqual(elem.attrib, {'b1': 'false', 'b2': 'false', 'b3': 'false'}) def test_encode_sub_tree(self): """Test encoding data of a non-root element""" data = { "@id": "PAR", "name": "Pierre-Auguste Renoir", "born": "1841-02-25", "dead": "1919-12-03", "qualification": "painter", } elem = self.col_schema.encode( data, path=".//author", namespaces=self.col_namespaces, ) self.assertEqual( etree_tostring(elem), dedent( """\ <author id="PAR"> <name>Pierre-Auguste Renoir</name> <born>1841-02-25</born> <dead>1919-12-03</dead> <qualification>painter</qualification> </author>""" ) ) @unittest.skipIf(lxml_etree is None, "The lxml library is not available.") def test_lxml_encode(self): """Test encode with etree_element_class=lxml.etree.Element""" xd = { "@xmlns:col": "http://example.com/ns/collection", "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance", "@xsi:schemaLocation": "http://example.com/ns/collection collection.xsd", "object": [ { "@id": "b0836217463", "@available": True, "position": 2, "title": None, "year": "1925", "author": { "@id": "JM", "name": "Joan Miró", "born": "1893-04-20", "dead": "1983-12-25", "qualification": "painter, sculptor and ceramicist", }, }, ], } elem = self.col_schema.encode( xd, path="./col:collection", namespaces=self.col_namespaces, etree_element_class=lxml_etree.Element, ) self.assertEqual( etree_tostring(elem, namespaces=self.col_namespaces), dedent( """\ <col:collection xmlns:col="http://example.com/ns/collection" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ns/collection collection.xsd"> <object id="b0836217463" available="true"> <position>2</position> <title/> <year>1925</year> <author id="JM"> <name>Joan Miró</name> <born>1893-04-20</born> <dead>1983-12-25</dead> <qualification>painter, sculptor and ceramicist</qualification> </author> </object> </col:collection>""" ) ) class TestEncoding11(TestEncoding): schema_class = XMLSchema11 if __name__ == '__main__': import platform header_template = "Test xmlschema encoding with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validation/test_validation.py������������������������������������������������0000664�0000000�0000000�00000034414�14211403446�0022616�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import sys import decimal from textwrap import dedent try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None import xmlschema from xmlschema import XMLSchemaValidationError from xmlschema.etree import ElementTree from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase class TestValidation(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') def check_validity(self, xsd_component, data, expected, use_defaults=True): if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, xsd_component.is_valid, data, use_defaults=use_defaults) elif expected: self.assertTrue(xsd_component.is_valid(data, use_defaults=use_defaults)) else: self.assertFalse(xsd_component.is_valid(data, use_defaults=use_defaults)) @unittest.skipIf(lxml_etree is None, "The lxml library is not available.") def test_lxml(self): xs = xmlschema.XMLSchema(self.casepath('examples/vehicles/vehicles.xsd')) xt1 = lxml_etree.parse(self.casepath('examples/vehicles/vehicles.xml')) xt2 = lxml_etree.parse(self.casepath('examples/vehicles/vehicles-1_error.xml')) self.assertTrue(xs.is_valid(xt1)) self.assertFalse(xs.is_valid(xt2)) self.assertTrue(xs.validate(xt1) is None) self.assertRaises(xmlschema.XMLSchemaValidationError, xs.validate, xt2) def test_document_validate_api(self): self.assertIsNone(xmlschema.validate(self.vh_xml_file)) self.assertIsNone(xmlschema.validate(self.vh_xml_file, use_defaults=False)) vh_2_file = self.casepath('examples/vehicles/vehicles-2_errors.xml') self.assertRaises(XMLSchemaValidationError, xmlschema.validate, vh_2_file) try: xmlschema.validate(vh_2_file, namespaces={'vhx': "http://example.com/vehicles"}) except XMLSchemaValidationError as err: path_line = str(err).splitlines()[-1] else: path_line = '' if sys.version_info >= (3, 6): self.assertEqual('Path: /vhx:vehicles/vhx:cars', path_line) else: self.assertTrue( 'Path: /vh:vehicles/vh:cars' == path_line or 'Path: /vhx:vehicles/vhx:cars', path_line ) # Due to unordered dicts # Issue #80 vh_2_xt = ElementTree.parse(vh_2_file) self.assertRaises(XMLSchemaValidationError, xmlschema.validate, vh_2_xt, self.vh_xsd_file) # Issue #145 with open(self.vh_xml_file) as f: self.assertIsNone(xmlschema.validate(f, schema=self.vh_xsd_file)) def test_document_validate_api_lazy(self): source = xmlschema.XMLResource(self.col_xml_file, lazy=False) namespaces = source.get_namespaces() source.root[0].clear() # Drop internal elements source.root[1].clear() xsd_element = self.col_schema.elements['collection'] self.assertRaises(XMLSchemaValidationError, xsd_element.decode, source.root, namespaces=namespaces) for _ in xsd_element.iter_decode(source.root, 'strict', namespaces=namespaces, source=source, max_depth=1): del _ self.assertIsNone(xmlschema.validate(self.col_xml_file, lazy=True)) def test_document_is_valid_api(self): self.assertTrue(xmlschema.is_valid(self.vh_xml_file)) self.assertTrue(xmlschema.is_valid(self.vh_xml_file, use_defaults=False)) vh_2_file = self.casepath('examples/vehicles/vehicles-2_errors.xml') self.assertFalse(xmlschema.is_valid(vh_2_file)) def test_document_iter_errors_api(self): self.assertListEqual(list(xmlschema.iter_errors(self.vh_xml_file)), []) self.assertListEqual(list(xmlschema.iter_errors(self.vh_xml_file, use_defaults=False)), []) vh_2_file = self.casepath('examples/vehicles/vehicles-2_errors.xml') errors = list(xmlschema.iter_errors(vh_2_file)) self.assertEqual(len(errors), 2) self.assertIsInstance(errors[0], XMLSchemaValidationError) self.assertIsInstance(errors[1], XMLSchemaValidationError) def test_max_depth_argument(self): schema = self.schema_class(self.col_xsd_file) invalid_col_xml_file = self.casepath('examples/collection/collection-1_error.xml') self.assertFalse(schema.is_valid(invalid_col_xml_file)) self.assertTrue(schema.is_valid(invalid_col_xml_file, max_depth=1)) self.assertTrue(schema.is_valid(invalid_col_xml_file, max_depth=2)) self.assertFalse(schema.is_valid(invalid_col_xml_file, max_depth=3)) root = ElementTree.parse(invalid_col_xml_file).getroot() xsd_element = schema.elements['collection'] self.assertFalse(xsd_element.is_valid(root)) self.assertTrue(xsd_element.is_valid(root, max_depth=1)) self.assertTrue(xsd_element.is_valid(root, max_depth=2)) self.assertFalse(xsd_element.is_valid(root, max_depth=3)) # Need to provide namespace explicitly because the default namespace # is set with xpathDefaultNamespace, that is '' in this case. xsd_element = schema.find('collection/object', namespaces={'': schema.target_namespace}) self.assertTrue(xsd_element.is_valid(root[0])) self.assertFalse(xsd_element.is_valid(root[1])) self.assertTrue(xsd_element.is_valid(root[1], max_depth=1)) self.assertFalse(xsd_element.is_valid(root[1], max_depth=2)) def test_extra_validator(self): # Related to issue 227 def bikes_validator(elem, xsd_element_): if elem.tag == '{http://example.com/vehicles}bike' and \ xsd_element_.name == elem.tag and \ elem.attrib['make'] != 'Harley-Davidson': raise XMLSchemaValidationError(xsd_element_, elem, 'not an Harley-Davidson') with self.assertRaises(XMLSchemaValidationError) as ec: self.vh_schema.validate(self.vh_xml_file, extra_validator=bikes_validator) self.assertIn('Reason: not an Harley-Davidson', str(ec.exception)) root = ElementTree.parse(self.vh_xml_file).getroot() xsd_element = self.vh_schema.elements['vehicles'] with self.assertRaises(XMLSchemaValidationError) as ec: xsd_element.validate(root, extra_validator=bikes_validator) self.assertIn('Reason: not an Harley-Davidson', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError) as ec: self.vh_schema.decode(self.vh_xml_file, extra_validator=bikes_validator) self.assertIn('Reason: not an Harley-Davidson', str(ec.exception)) def bikes_validator(elem, xsd_element_): if elem.tag == '{http://example.com/vehicles}bike' and \ xsd_element_.name == elem.tag and \ elem.attrib['make'] != 'Harley-Davidson': yield XMLSchemaValidationError(xsd_element_, elem, 'not an Harley-Davidson') with self.assertRaises(XMLSchemaValidationError) as ec: self.vh_schema.validate(self.vh_xml_file, extra_validator=bikes_validator) self.assertIn('Reason: not an Harley-Davidson', str(ec.exception)) def test_issue_064(self): self.check_validity(self.st_schema, '<name xmlns="ns"></name>', False) def test_issue_171(self): # First schema has an assert with naive check schema = xmlschema.XMLSchema11(self.casepath('issues/issue_171/issue_171.xsd')) self.check_validity(schema, '<tag name="test" abc="10" def="0"/>', False) self.check_validity(schema, '<tag name="test" abc="10" def="1"/>', False) self.check_validity(schema, '<tag name="test" abc="10"/>', True) # Same schema with a more reliable assert expression schema = xmlschema.XMLSchema11(self.casepath('issues/issue_171/issue_171b.xsd')) self.check_validity(schema, '<tag name="test" abc="10" def="0"/>', False) self.check_validity(schema, '<tag name="test" abc="10" def="1"/>', False) self.check_validity(schema, '<tag name="test" abc="10"/>', True) # Another schema with a simple assert expression to test that EBV of abc/def='0' is True schema = xmlschema.XMLSchema11(self.casepath('issues/issue_171/issue_171c.xsd')) self.check_validity(schema, '<tag name="test" abc="0" def="1"/>', True) self.check_validity(schema, '<tag name="test" abc="1" def="0"/>', True) self.check_validity(schema, '<tag name="test" abc="1" def="1"/>', True) self.check_validity(schema, '<tag name="test" abc="0" def="0"/>', True) self.check_validity(schema, '<tag name="test" abc="1"/>', False) self.check_validity(schema, '<tag name="test" def="1"/>', False) def test_issue_183(self): # Test for issue #183 schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns0="http://xmlschema.test/0" xmlns:tns1="http://xmlschema.test/1" xmlns="http://xmlschema.test/2" targetNamespace="http://xmlschema.test/0"> <xs:element name="elem1" type="xs:string"/> <xs:element name="elem2" type="xs:string"/> <xs:element name="root" type="tns0:enumType"/> <xs:simpleType name="enumType"> <xs:restriction base="xs:QName"> <xs:enumeration value="tns0:elem1"/> <xs:enumeration value="tns0:elem2"/> <xs:enumeration value="tns1:elem1"/> <xs:enumeration value="elem1"/> </xs:restriction> </xs:simpleType> </xs:schema>""") xml_data = '<tns0:root xmlns:tns0="http://xmlschema.test/0" >tns0:elem1</tns0:root>' self.check_validity(schema, xml_data, True) xml_data = '<ns0:root xmlns:ns0="http://xmlschema.test/0" >ns0:elem1</ns0:root>' self.check_validity(schema, xml_data, True) self.assertEqual(schema.decode(xml_data), 'ns0:elem1') schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://xmlschema.test/0" xmlns:tns1="http://xmlschema.test/1" xmlns:tns2="http://xmlschema.test/2" targetNamespace="http://xmlschema.test/0"> <xs:element name="elem1" type="xs:string"/> <xs:element name="elem2" type="xs:string"/> <xs:element name="elem3" type="xs:string"/> <xs:element name="elem4" type="xs:string"/> <xs:element name="root" type="enumType"/> <xs:simpleType name="enumType"> <xs:restriction base="xs:QName"> <xs:enumeration value="elem1"/> <xs:enumeration value="elem2"/> <xs:enumeration value="tns1:other1"/> <xs:enumeration value="elem3"/> <xs:enumeration value="tns2:other2"/> <xs:enumeration value="elem4"/> </xs:restriction> </xs:simpleType> </xs:schema>""") xml_data = '<ns0:root xmlns:ns0="http://xmlschema.test/0">ns0:elem2</ns0:root>' self.check_validity(schema, xml_data, True) def test_issue_213(self): schema = xmlschema.XMLSchema(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="amount" type="xs:decimal"/> </xs:schema>""")) xml1 = """<?xml version="1.0" encoding="UTF-8"?><amount>0.000000</amount>""" self.assertIsInstance(schema.decode(xml1), decimal.Decimal) xml2 = """<?xml version="1.0" encoding="UTF-8"?><amount>0.0000000</amount>""" self.assertIsInstance(schema.decode(xml2), decimal.Decimal) def test_issue_224__validate_malformed_file(self): schema = xmlschema.XMLSchema(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:string"/> </xs:schema>""")) malformed_xml_file = self.casepath('resources/malformed.xml') with self.assertRaises(ElementTree.ParseError): schema.is_valid(malformed_xml_file) def test_issue_238__validate_bytes_strings(self): schema = xmlschema.XMLSchema(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="value" type="xs:int"/> </xs:schema>""")) self.assertTrue(schema.is_valid('<value>11</value>')) self.assertTrue(schema.is_valid(b'<value>\n11\n</value>')) with open(self.col_xml_file, 'rb') as fp: col_xml_data = fp.read() self.assertIsInstance(col_xml_data, bytes) self.assertTrue(self.col_schema.is_valid(col_xml_data)) class TestValidation11(TestValidation): schema_class = XMLSchema11 def test_default_attributes(self): xs = self.schema_class(self.casepath('features/attributes/default_attributes.xsd')) self.assertTrue(xs.is_valid("<tree xmlns='ns'>\n" " <node node-id='1'>alpha</node>\n" " <node node-id='2' colour='red'>beta</node>\n" "</tree>")) self.assertFalse(xs.is_valid("<tree xmlns='ns'>\n" " <node>alpha</node>\n" # Misses required attribute " <node node-id='2' colour='red'>beta</node>\n" "</tree>")) if __name__ == '__main__': import platform header_template = "Test xmlschema validation with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017063�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/__init__.py�������������������������������������������������������0000664�0000000�0000000�00000000000�14211403446�0021162�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_attributes.py������������������������������������������������0000664�0000000�0000000�00000063710�14211403446�0022671�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from textwrap import dedent from xmlschema import XMLSchemaParseError, XMLSchemaValidationError from xmlschema.validators import XMLSchema11, XsdAttribute, XsdAttributeGroup from xmlschema.testing import XsdValidatorTestCase from xmlschema.names import XSI_NAMESPACE, XSD_ANY_SIMPLE_TYPE, XSD_STRING class TestXsdAttributes(XsdValidatorTestCase): def test_attribute_use(self): schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:string"/> </xs:attributeGroup>""") self.assertTrue(schema.attribute_groups['extra']['label'].is_optional()) self.assertFalse(schema.attribute_groups['extra']['label'].is_required()) self.assertFalse(schema.attribute_groups['extra']['label'].is_prohibited()) schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:string" use="required"/> </xs:attributeGroup>""") self.assertFalse(schema.attribute_groups['extra']['label'].is_optional()) self.assertTrue(schema.attribute_groups['extra']['label'].is_required()) self.assertFalse(schema.attribute_groups['extra']['label'].is_prohibited()) schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:string" use="prohibited"/> </xs:attributeGroup>""") self.assertNotIn('label', schema.attribute_groups['extra']) with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema('<xs:attribute name="label" type="xs:string" use="optional"/>') self.assertEqual("use of attribute 'use' is prohibited", ctx.exception.message) with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:string" use="mandatory"/> </xs:attributeGroup>""") self.assertEqual(ctx.exception.message, "attribute use='mandatory': value must " "be one of ['prohibited', 'optional', 'required']") with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:string" use=""/> </xs:attributeGroup>""") self.assertEqual(ctx.exception.message, "attribute use='': value doesn't match any pattern of ['\\\\c+']") def test_is_empty_attribute(self): schema = self.check_schema(""" <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string" fixed=""/> <xs:attribute name="a3" type="emptyString"/> <xs:simpleType name="emptyString"> <xs:restriction base="xs:string"> <xs:maxLength value="0"/> </xs:restriction> </xs:simpleType> """) self.assertFalse(schema.attributes['a1'].is_empty()) self.assertTrue(schema.attributes['a2'].is_empty()) self.assertTrue(schema.attributes['a3'].is_empty()) def test_wrong_attribute_type(self): self.check_schema(""" <xs:attributeGroup name="alpha"> <xs:attribute name="name" type="xs:anyType"/> </xs:attributeGroup> """, XMLSchemaParseError) def test_attribute_reference(self): self.check_schema(""" <xs:attributeGroup name="contact"> <xs:attribute name="name" type="xs:string"/> <xs:attribute ref="phone"/> <!-- Missing "phone" attribute --> </xs:attributeGroup> """, XMLSchemaParseError) schema = self.schema_class("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified"> <xs:attributeGroup name="contact"> <xs:attribute name="name" type="xs:string"/> <xs:attribute ref="phone"/> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string" default="555-0100"/> </xs:schema>""") xsd_attribute = schema.attribute_groups['contact']['phone'] self.assertTrue(xsd_attribute.qualified) self.assertEqual(xsd_attribute.default, '555-0100') schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone"/> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string" fixed="555-0100"/> """) xsd_attribute = schema.attribute_groups['extra']['phone'] self.assertEqual(xsd_attribute.fixed, '555-0100') self.assertIsNone(xsd_attribute.annotation) schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone" fixed="555-0100"> <xs:annotation/> </xs:attribute> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string" fixed="555-0100"/> """) xsd_attribute = schema.attribute_groups['extra']['phone'] self.assertEqual(xsd_attribute.fixed, '555-0100') self.assertIsNotNone(xsd_attribute.annotation) self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone" fixed="555-0101"/> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string" fixed="555-0100"/> """, XMLSchemaParseError) with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone"> <xs:simpleType> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:attribute> </xs:attributeGroup>""") self.assertEqual("a reference component cannot have child definitions/declarations", ctx.exception.message) def test_name_attribute(self): with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema('<xs:attribute type="xs:string"/>') self.assertEqual(ctx.exception.message, "missing required attribute 'name'") schema = self.check_schema('<xs:attribute type="xs:string"/>', validation='lax') self.assertEqual(len(schema.all_errors), 2) self.assertEqual(schema.all_errors[0].message, "missing required attribute 'name'") self.assertIn("missing key field '@name'", schema.all_errors[1].message) self.assertEqual(len(schema.attributes), 0) schema = self.check_schema('<xs:attribute type="xs:string"/>', validation='skip') self.assertEqual(len(schema.all_errors), 0) xsd_attribute = XsdAttribute(elem=schema.root[0], schema=schema, parent=None) self.assertIsNone(xsd_attribute.name) self.assertEqual(xsd_attribute.validation_attempted, 'full') with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema('<xs:attribute name="xmlns" type="xs:string"/>') self.assertEqual(ctx.exception.message, "an attribute name must be different from 'xmlns'") with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/2001/XMLSchema-instance" > <xs:attribute name="phone" type="xs:string"/> </xs:schema>""") self.assertEqual(ctx.exception.message, "cannot add attributes in %r namespace" % XSI_NAMESPACE) def test_type_attribute(self): schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone" type="xs:string"/> </xs:attributeGroup>""") self.assertEqual(schema.attribute_groups['extra']['phone'].type.name, XSD_STRING) schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone"/> </xs:attributeGroup>""") self.assertEqual(schema.attribute_groups['extra']['phone'].type.name, XSD_ANY_SIMPLE_TYPE) schema = self.check_schema('<xs:attribute name="foo" type="xs:foo"/>', validation='lax') self.assertEqual(schema.attributes['foo'].type.name, XSD_ANY_SIMPLE_TYPE) schema = self.check_schema('<xs:attribute name="foo" type="x:string"/>', validation='lax') self.assertEqual(schema.attributes['foo'].type.name, XSD_ANY_SIMPLE_TYPE) self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone" type="xs:string"/> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string"/> """, XMLSchemaParseError) with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:attribute name="phone" type="xs:string"> <xs:simpleType> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:attribute>""") self.assertEqual("ambiguous type definition for XSD attribute", ctx.exception.message) def test_form_attribute(self): schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone" type="xs:string" form="qualified"/> </xs:attributeGroup>""") self.assertTrue(schema.attribute_groups['extra']['phone'].qualified) self.assertEqual(schema.attribute_groups['extra']['phone'].form, 'qualified') schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone" type="xs:string" form="unqualified"/> </xs:attributeGroup>""") self.assertFalse(schema.attribute_groups['extra']['phone'].qualified) self.assertEqual(schema.attribute_groups['extra']['phone'].form, 'unqualified') schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone" type="xs:string"/> </xs:attributeGroup>""") self.assertFalse(schema.attribute_groups['extra']['phone'].qualified) self.assertIsNone(schema.attribute_groups['extra']['phone'].form) self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="phone" type="xs:string" form="mixed"/> </xs:attributeGroup>""", XMLSchemaParseError) self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute ref="phone" form="qualified"/> </xs:attributeGroup> <xs:attribute name="phone" type="xs:string"/> """, XMLSchemaParseError) def test_default_value(self): schema = self.check_schema( '<xs:attribute name="phone" type="xs:string" default="555-0100"/>' ) schema.attributes['phone'].default = '555-0100' with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attribute name="foo" type="xs:string" default="555-0100" fixed=""/>') self.assertEqual(ctx.exception.message, "'default' and 'fixed' attributes are mutually exclusive") with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attributeGroup name="extra">' ' <xs:attribute name="foo" type="xs:string" default="555-0100" use="required"/>' '</xs:attributeGroup>') self.assertEqual(ctx.exception.message, "the attribute 'use' must be 'optional' " "if the attribute 'default' is present") with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attribute name="foo" type="xs:int" default="555-0100"/>') self.assertTrue(ctx.exception.message.startswith("default value '555-0100' " "is not compatible with")) if self.schema_class.XSD_VERSION == "1.0": with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attribute name="foo" type="xs:ID" default="XYZ"/>') self.assertEqual(ctx.exception.message, "xs:ID key attributes cannot have a default value") def test_fixed_value(self): with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attribute name="foo" type="xs:int" fixed="555-0100"/>') self.assertTrue(ctx.exception.message.startswith("fixed value '555-0100' " "is not compatible with")) if self.schema_class.XSD_VERSION == "1.0": with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema( '<xs:attribute name="foo" type="xs:ID" fixed="XYZ"/>') self.assertEqual(ctx.exception.message, "xs:ID key attributes cannot have a fixed value") def test_attribute_group_mapping(self): schema = self.get_schema(""" <xs:attributeGroup name="attrs"> <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> </xs:attributeGroup>""") attribute_group = schema.attribute_groups['attrs'] self.assertEqual(repr(attribute_group), "XsdAttributeGroup(name='attrs')") with self.assertRaises(ValueError) as ec: attribute_group['a3'] = attribute_group['a2'] self.assertEqual("'a2' name and key 'a3' mismatch", str(ec.exception)) xsd_attribute = attribute_group['a2'] del attribute_group['a2'] self.assertNotIn('a2', attribute_group) attribute_group['a2'] = xsd_attribute def test_attribute_group_reference(self): schema = self.get_schema(""" <xs:attributeGroup name="alpha"> <xs:attribute name="name" type="xs:string"/> <xs:attributeGroup ref="beta"/> </xs:attributeGroup> <xs:attributeGroup name="beta"> <xs:attribute name="foo" type="xs:string"/> <xs:attribute name="bar" type="xs:string"/> </xs:attributeGroup>""") # ref="beta" does not imply a reference but only a copy # of the attributes of referred attribute group. attribute_group = schema.attribute_groups['alpha'] self.assertNotIn('beta', attribute_group) self.assertEqual(len(attribute_group), 3) self.assertIn('name', attribute_group) self.assertIn('foo', attribute_group) self.assertIn('bar', attribute_group) def test_missing_attribute_group_name(self): schema = self.get_schema(""" <xs:attributeGroup> <xs:annotation/> <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> </xs:attributeGroup>""", validation='lax') self.assertEqual(len(schema.all_errors), 2) self.assertTrue(isinstance(schema.all_errors[0], XMLSchemaParseError)) self.assertIn("missing required attribute 'name'", str(schema.all_errors[0])) self.assertTrue(isinstance(schema.all_errors[1], XMLSchemaParseError)) self.assertIn("missing key field '@name'", str(schema.all_errors[1])) self.assertEqual(len(schema.attribute_groups), 0) attribute_group = XsdAttributeGroup(schema.root[0], schema, parent=None) self.assertIsNone(attribute_group.name) def test_missing_attribute_group_reference(self): self.check_schema(""" <xs:attributeGroup name="alpha"> <xs:attribute name="name" type="xs:string"/> <xs:attributeGroup ref="beta"/> <!-- Missing "beta" attribute group --> </xs:attributeGroup> """, XMLSchemaParseError) self.check_schema(""" <xs:attributeGroup name="alpha"> <xs:attribute name="name" type="xs:string"/> <xs:attributeGroup ref="x:beta"/> <!-- Unresolved name --> </xs:attributeGroup> <xs:attributeGroup name="beta"> <xs:attribute name="foo" type="xs:string"/> <xs:attribute name="bar" type="xs:string"/> </xs:attributeGroup> """, XMLSchemaParseError) schema = self.get_schema(""" <xs:attributeGroup name="alpha"> <xs:attribute name="name" type="xs:string"/> <xs:attributeGroup name="beta"/> <!-- attribute "name" instead of "ref" --> </xs:attributeGroup> """, validation='lax') self.assertTrue(isinstance(schema.all_errors[1], XMLSchemaParseError)) def test_attribute_wildcards(self): schema = self.get_schema(""" <xs:attributeGroup name="attrs"> <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> <xs:anyAttribute namespace="other"/> </xs:attributeGroup>""") attribute_group = schema.attribute_groups['attrs'] self.assertEqual(len(attribute_group), 3) self.assertIn(None, attribute_group) schema = self.get_schema(""" <xs:attributeGroup name="attrs"> <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> <xs:anyAttribute namespace="other"/> <xs:anyAttribute namespace="#all"/> <xs:attribute name="a3" type="xs:string"/> </xs:attributeGroup>""", validation='lax') self.assertEqual(len(schema.all_errors), 3) self.assertTrue(isinstance(schema.all_errors[0], XMLSchemaParseError)) self.assertIn("Unexpected child with tag 'xs:anyAttribute'", str(schema.all_errors[0])) self.assertTrue(isinstance(schema.all_errors[1], XMLSchemaParseError)) self.assertIn("more anyAttribute declarations", str(schema.all_errors[1])) self.assertTrue(isinstance(schema.all_errors[2], XMLSchemaParseError)) self.assertIn("another declaration after anyAttribute", str(schema.all_errors[2])) def test_duplicated_attribute(self): with self.assertRaises(XMLSchemaParseError) as ec: self.get_schema(""" <xs:attributeGroup name="attrs"> <xs:attribute name="a1" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> <xs:attribute name="a2" type="xs:string"/> </xs:attributeGroup>""") self.assertIn("multiple declaration for attribute 'a2'", str(ec.exception)) def test_duplicated_attribute_group_ref(self): with self.assertRaises(XMLSchemaParseError) as ec: self.get_schema(""" <xs:attributeGroup name="attrs"> <xs:attribute name="a1" type="xs:string"/> <xs:attributeGroup ref="other"/> <xs:attributeGroup ref="other"/> </xs:attributeGroup> <xs:attributeGroup name="other"> <xs:attribute name="a2" type="xs:string"/> <xs:attribute name="a3" type="xs:string"/> </xs:attributeGroup>""") self.assertIn("duplicated attributeGroup 'other'", str(ec.exception)) def test_scope_property(self): schema = self.check_schema(""" <xs:attribute name="global_attr" type="xs:string"/> <xs:attributeGroup name="attrGroup"> <xs:attribute name="local_attr" type="xs:string"/> </xs:attributeGroup> """) self.assertEqual(schema.attributes['global_attr'].scope, 'global') self.assertEqual(schema.attribute_groups['attrGroup']['local_attr'].scope, 'local') def test_value_constraint_property(self): schema = self.check_schema(""" <xs:attributeGroup name="attrGroup"> <xs:attribute name="attr1" type="xs:string"/> <xs:attribute name="attr2" type="xs:string" default="alpha"/> <xs:attribute name="attr3" type="xs:string" default="beta"/> </xs:attributeGroup> """) attribute_group = schema.attribute_groups['attrGroup'] self.assertIsNone(attribute_group['attr1'].value_constraint) self.assertEqual(attribute_group['attr2'].value_constraint, 'alpha') self.assertEqual(attribute_group['attr3'].value_constraint, 'beta') def test_decoding(self): schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="code" type="xs:int"/> <xs:attribute name="phone" type="xs:string" default="555-0100"/> </xs:attributeGroup>""") xsd_attribute = schema.attribute_groups['extra']['phone'] self.assertEqual(xsd_attribute.decode(None), '555-0100') self.assertEqual(schema.attribute_groups['extra'].decode({'code': '682'}), [('code', 682), ('phone', '555-0100')]) schema = self.check_schema( """<xs:attribute name="phone" type="xs:string" fixed="555-0100"/>""") xsd_attribute = schema.attributes['phone'] self.assertEqual(xsd_attribute.decode(None), '555-0100') self.assertEqual(xsd_attribute.decode('555-0100'), '555-0100') with self.assertRaises(XMLSchemaValidationError) as ctx: xsd_attribute.decode('555-0101') self.assertEqual(ctx.exception.reason, "attribute 'phone' has a fixed value '555-0100'") def test_decoding_notation_type(self): schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label" type="xs:NOTATION"/> </xs:attributeGroup>""") with self.assertRaises(XMLSchemaValidationError) as ctx: schema.attribute_groups['extra'].decode({'label': 'alpha'}) self.assertTrue(ctx.exception.reason.startswith("cannot validate against xs:NOTATION")) schema = self.check_schema(""" <xs:attributeGroup name="extra"> <xs:attribute name="label"> <xs:simpleType> <xs:restriction base="xs:NOTATION"/> </xs:simpleType> </xs:attribute> </xs:attributeGroup>""") with self.assertRaises(XMLSchemaValidationError) as ctx: schema.attribute_groups['extra'].decode({'label': 'alpha'}) self.assertEqual(ctx.exception.reason, "missing enumeration facet in xs:NOTATION subtype") schema = self.check_schema(""" <xs:notation name="jpeg" public="image/jpeg"/> <xs:notation name="png" public="image/png"/> <xs:attributeGroup name="extra"> <xs:attribute name="label"> <xs:simpleType> <xs:restriction base="xs:NOTATION"> <xs:enumeration value="jpeg"/> <xs:enumeration value="png"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:attributeGroup>""") with self.assertRaises(XMLSchemaValidationError) as ctx: schema.attribute_groups['extra'].decode({'label': 'alpha'}) self.assertIn("value must be one of ['jpeg', 'png']", ctx.exception.reason) class TestXsd11Attributes(TestXsdAttributes): schema_class = XMLSchema11 def test_target_namespace(self): xs = self.get_schema('<xs:attribute name="a" type="xs:string"/>') self.assertEqual(xs.attributes['a'].target_namespace, '') with self.assertRaises(XMLSchemaParseError) as ec: self.get_schema('<xs:attribute name="foo" targetNamespace="bar" type="xs:string"/>') self.assertIn("'targetNamespace' is prohibited", str(ec.exception)) xs = self.get_schema(dedent("""\ <xs:attributeGroup name="attrs"> <xs:attribute name="a" type="xs:string" targetNamespace="http://xmlschema.test/ns"/> <xs:attribute ref="b"/> </xs:attributeGroup> <xs:attribute name="b" type="xs:string"/>""")) self.assertNotIn('a', xs.attribute_groups['attrs']) self.assertIn('{http://xmlschema.test/ns}a', xs.attribute_groups['attrs']) xsd_attribute = xs.attribute_groups['attrs']['{http://xmlschema.test/ns}a'] self.assertEqual(xsd_attribute.target_namespace, 'http://xmlschema.test/ns') self.assertEqual(xs.attribute_groups['attrs']['b'].target_namespace, '') def test_prohibited_and_fixed_incompatibility(self): with self.assertRaises(XMLSchemaParseError) as ec: self.get_schema(dedent("""\ <xs:attributeGroup name="attrs"> <xs:attribute name="a" type="xs:string" use="prohibited" fixed="foo"/> </xs:attributeGroup>""")) self.assertIn("'fixed' with use=prohibited is not allowed in XSD 1.1", str(ec.exception)) def test_inheritable_attribute(self): xs = self.get_schema(dedent("""\ <xs:attributeGroup name="attrs"> <xs:attribute name="a" type="xs:string" /> <xs:attribute name="b" type="xs:string" inheritable="true"/> <xs:attribute name="c" type="xs:string" inheritable="false"/> </xs:attributeGroup>""")) self.assertFalse(xs.attribute_groups['attrs']['a'].inheritable) self.assertTrue(xs.attribute_groups['attrs']['b'].inheritable) self.assertFalse(xs.attribute_groups['attrs']['c'].inheritable) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD attributes with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ��������������������������������������������������������xmlschema-1.10.0/tests/validators/test_builtins.py��������������������������������������������������0000664�0000000�0000000�00000034020�14211403446�0022324�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests on XSD meta schema and XSD builtins""" import unittest from textwrap import dedent from xmlschema import XMLSchemaDecodeError, XMLSchemaEncodeError, \ XMLSchemaValidationError, XMLSchema10, XMLSchema11 from xmlschema.names import XSD_STRING from xmlschema.helpers import is_etree_element from xmlschema.validators.builtins import XSD_10_BUILTIN_TYPES, \ XSD_11_BUILTIN_TYPES, xsd_builtin_types_factory class TestXsd10BuiltinTypes(unittest.TestCase): @classmethod def setUpClass(cls): cls.schema_class = XMLSchema10 cls.types = XMLSchema10.builtin_types() @classmethod def tearDownClass(cls): XMLSchema10.meta_schema.clear() def test_facet_lists(self): for builtin_types in (XSD_10_BUILTIN_TYPES, XSD_11_BUILTIN_TYPES): for item in builtin_types: if 'facets' in item: self.assertIsInstance(item['facets'], list) self.assertLessEqual(len([e for e in item['facets'] if callable(e)]), 1) for e in item['facets']: self.assertTrue(callable(e) or is_etree_element(e)) def test_factory(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>"""), use_meta=False, build=False) with self.assertRaises(ValueError) as ctx: xsd_types = {XSD_STRING: (None, schema)} xsd_builtin_types_factory(schema.meta_schema, xsd_types) self.assertEqual(str(ctx.exception), "loaded entry schema is not the meta-schema!") def test_boolean_decode(self): boolean_type = self.types['boolean'] self.assertTrue(boolean_type.decode(' true \n') is True) self.assertTrue(boolean_type.decode(' 0 \n') is False) self.assertTrue(boolean_type.decode(' 1 \n') is True) self.assertTrue(boolean_type.decode(' false \n') is False) self.assertRaises(XMLSchemaDecodeError, boolean_type.decode, ' 1.0 ') self.assertRaises(XMLSchemaDecodeError, boolean_type.decode, ' alpha \n') def test_boolean_encode(self): boolean_type = self.types['boolean'] self.assertTrue(boolean_type.encode(True) == 'true') self.assertTrue(boolean_type.encode(False) == 'false') self.assertRaises(XMLSchemaEncodeError, boolean_type.encode, 1) self.assertRaises(XMLSchemaEncodeError, boolean_type.encode, 0) self.assertRaises(XMLSchemaEncodeError, boolean_type.encode, 10) self.assertRaises(XMLSchemaEncodeError, boolean_type.encode, 'alpha') def test_integer_decode(self): integer_type = self.types['integer'] self.assertTrue(integer_type.decode(' 1000 \n') == 1000) self.assertTrue(integer_type.decode(' -19 \n') == -19) self.assertTrue(integer_type.decode(' 0\n') == 0) self.assertRaises(XMLSchemaDecodeError, integer_type.decode, ' 1000.0 \n') self.assertRaises(XMLSchemaDecodeError, integer_type.decode, ' alpha \n') self.assertRaises(XMLSchemaValidationError, self.types['byte'].decode, ' 257 \n') self.assertRaises(XMLSchemaValidationError, self.types['unsignedInt'].decode, ' -1') def test_integer_encode(self): integer_type = self.types['integer'] self.assertTrue(integer_type.encode(1000) == '1000') self.assertTrue(integer_type.encode(-19) == '-19') self.assertTrue(integer_type.encode(0) == '0') self.assertRaises(XMLSchemaEncodeError, integer_type.encode, 10.1) self.assertRaises(XMLSchemaEncodeError, integer_type.encode, 'alpha') self.assertRaises(XMLSchemaValidationError, self.types['unsignedInt'].decode, ' -1') def test_float_decode(self): self.assertTrue(self.types['float'].decode(' 1000.1 \n') == 1000.10) self.assertTrue(self.types['float'].decode(' -19 \n') == -19.0) self.assertTrue(self.types['double'].decode(' 0.0001\n') == 0.0001) self.assertRaises(XMLSchemaValidationError, self.types['float'].decode, ' true ') self.assertRaises(XMLSchemaValidationError, self.types['double'].decode, ' alpha \n') def test_float_encode(self): float_type = self.types['float'] self.assertTrue(float_type.encode(1000.0) == '1000.0') self.assertTrue(float_type.encode(-19.0) == '-19.0') self.assertTrue(float_type.encode(0.0) == '0.0') self.assertRaises(XMLSchemaEncodeError, float_type.encode, True) self.assertRaises(XMLSchemaEncodeError, float_type.encode, 'alpha') def test_time_type(self): time_type = self.types['time'] self.assertTrue(time_type.is_valid('14:35:00')) self.assertTrue(time_type.is_valid('14:35:20.5345')) self.assertTrue(time_type.is_valid('14:35:00-01:00')) self.assertTrue(time_type.is_valid('14:35:00Z')) self.assertTrue(time_type.is_valid('00:00:00')) self.assertTrue(time_type.is_valid('24:00:00')) self.assertFalse(time_type.is_valid('4:20:00')) self.assertFalse(time_type.is_valid('14:35:0')) self.assertFalse(time_type.is_valid('14:35')) self.assertFalse(time_type.is_valid('14:35.5:00')) def test_datetime_type(self): datetime_type = self.types['dateTime'] self.assertTrue(datetime_type.is_valid('2007-05-10T14:35:00')) self.assertTrue(datetime_type.is_valid('2007-05-10T14:35:20.6')) self.assertTrue(datetime_type.is_valid('2007-05-10T14:35:00-03:00')) self.assertTrue(datetime_type.is_valid('2007-05-10T14:35:00Z')) self.assertFalse(datetime_type.is_valid('2007-05-10T14:35')) self.assertFalse(datetime_type.is_valid('2007-05-10t14:35:00')) self.assertFalse(datetime_type.is_valid('2007-05-1014:35:00')) self.assertFalse(datetime_type.is_valid('07-05-10T14:35:00')) self.assertFalse(datetime_type.is_valid('2007-05-10')) # Issue #85 self.assertTrue(datetime_type.is_valid('2018-10-10T13:57:53.0702116-04:00')) def test_date_type(self): date_type = self.types['date'] self.assertTrue(date_type.is_valid('2012-05-31')) self.assertTrue(date_type.is_valid('-0065-10-15')) self.assertTrue(date_type.is_valid('12012-05-31')) self.assertTrue(date_type.is_valid('2012-05-31-05:00')) self.assertTrue(date_type.is_valid('2015-06-30Z')) self.assertFalse(date_type.is_valid('12-05-31')) self.assertFalse(date_type.is_valid('2012-5-31')) self.assertFalse(date_type.is_valid('31-05-2012')) self.assertFalse(date_type.is_valid('1999-06-31')) self.assertFalse(date_type.is_valid('+2012-05-31')) self.assertFalse(date_type.is_valid('')) def test_year_zero(self): self.assertFalse(self.types['date'].is_valid('0000-01-01')) def test_g_year_type(self): g_year_type = self.types['gYear'] self.assertTrue(g_year_type.is_valid('2007')) self.assertTrue(g_year_type.is_valid('2013-01:00')) self.assertTrue(g_year_type.is_valid('102013-01:00')) self.assertTrue(g_year_type.is_valid('0821')) self.assertTrue(g_year_type.is_valid('0014')) self.assertTrue(g_year_type.is_valid('-0044')) self.assertTrue(g_year_type.is_valid('13999')) self.assertFalse(g_year_type.is_valid('045')) self.assertFalse(g_year_type.is_valid('800')) self.assertFalse(g_year_type.is_valid('')) def test_g_year_month_type(self): g_year_month_type = self.types['gYearMonth'] self.assertTrue(g_year_month_type.is_valid('2010-07')) self.assertTrue(g_year_month_type.is_valid('2020-01-05:00')) self.assertFalse(g_year_month_type.is_valid('99-02')) self.assertFalse(g_year_month_type.is_valid('1999')) self.assertFalse(g_year_month_type.is_valid('1995-3')) self.assertFalse(g_year_month_type.is_valid('1860-14')) self.assertFalse(g_year_month_type.is_valid('')) def test_g_month_type(self): g_month_type = self.types['gMonth'] self.assertTrue(g_month_type.is_valid('--08')) self.assertTrue(g_month_type.is_valid('--05-03:00')) self.assertFalse(g_month_type.is_valid('03')) self.assertFalse(g_month_type.is_valid('3')) self.assertFalse(g_month_type.is_valid('--13')) self.assertFalse(g_month_type.is_valid('--3')) self.assertFalse(g_month_type.is_valid('')) def test_g_month_day_type(self): g_month_day_type = self.types['gMonthDay'] self.assertTrue(g_month_day_type.is_valid('--12-24')) self.assertTrue(g_month_day_type.is_valid('--04-25Z')) self.assertFalse(g_month_day_type.is_valid('12-24')) self.assertFalse(g_month_day_type.is_valid('--11-31')) self.assertFalse(g_month_day_type.is_valid('--2-11')) self.assertFalse(g_month_day_type.is_valid('--02-1')) self.assertFalse(g_month_day_type.is_valid('')) def test_g_day_type(self): g_day_type = self.types['gDay'] self.assertTrue(g_day_type.is_valid('---19')) self.assertTrue(g_day_type.is_valid('---07')) self.assertFalse(g_day_type.is_valid('---32')) self.assertFalse(g_day_type.is_valid('07')) self.assertFalse(g_day_type.is_valid('--07')) self.assertFalse(g_day_type.is_valid('---7')) self.assertFalse(g_day_type.is_valid('')) def test_duration_type(self): duration_type = self.types['duration'] self.assertTrue(duration_type.is_valid('-P809YT3H5M5S')) self.assertTrue(duration_type.is_valid('P5Y7M20DT3H5M5S')) self.assertTrue(duration_type.is_valid('P1DT6H')) self.assertTrue(duration_type.is_valid('P15M')) self.assertTrue(duration_type.is_valid('PT30M')) self.assertTrue(duration_type.is_valid('P0Y15M0D')) self.assertTrue(duration_type.is_valid('P0Y')) self.assertTrue(duration_type.is_valid('-P10D')) self.assertTrue(duration_type.is_valid('PT5M30.5S')) self.assertTrue(duration_type.is_valid('PT10.5S')) self.assertFalse(duration_type.is_valid('P-50M')) self.assertFalse(duration_type.is_valid('P50MT')) self.assertFalse(duration_type.is_valid('P1YM7D')) self.assertFalse(duration_type.is_valid('P10.8Y')) self.assertFalse(duration_type.is_valid('P3D5H')) self.assertFalse(duration_type.is_valid('1Y')) self.assertFalse(duration_type.is_valid('P3D4M')) self.assertFalse(duration_type.is_valid('P')) self.assertFalse(duration_type.is_valid('PT10.S')) self.assertFalse(duration_type.is_valid('')) class TestXsd11BuiltinTypes(TestXsd10BuiltinTypes): @classmethod def setUpClass(cls): cls.schema_class = XMLSchema11 cls.types = XMLSchema11.builtin_types() @classmethod def tearDownClass(cls): XMLSchema11.meta_schema.clear() def test_year_zero(self): self.assertTrue(self.types['date'].is_valid('0000-01-01')) def test_date_time_stamp(self): date_time_stamp_type = self.types['dateTimeStamp'] self.assertTrue(date_time_stamp_type.is_valid('2003-10-20T16:50:08-03:00')) self.assertTrue(date_time_stamp_type.is_valid('2003-10-20T16:50:08Z')) self.assertFalse(date_time_stamp_type.is_valid('2003-10-20T16:50:08')) self.assertFalse(date_time_stamp_type.is_valid('1980-02-28T17:09:20.1')) self.assertFalse(date_time_stamp_type.is_valid('')) def test_day_time_duration_type(self): day_time_duration_type = self.types['dayTimeDuration'] self.assertTrue(day_time_duration_type.is_valid('P7DT15H40M0S')) self.assertTrue(day_time_duration_type.is_valid('-P10D')) self.assertTrue(day_time_duration_type.is_valid('P0D')) self.assertTrue(day_time_duration_type.is_valid('PT13M')) self.assertTrue(day_time_duration_type.is_valid('P0DT17M')) self.assertTrue(day_time_duration_type.is_valid('PT3H20M10.5S')) self.assertFalse(day_time_duration_type.is_valid('PT5D')) self.assertFalse(day_time_duration_type.is_valid('PT3HM10S')) self.assertFalse(day_time_duration_type.is_valid('P7DT')) self.assertFalse(day_time_duration_type.is_valid('PT3H1.4M')) self.assertFalse(day_time_duration_type.is_valid('P-5D')) self.assertFalse(day_time_duration_type.is_valid('P1D5H')) self.assertFalse(day_time_duration_type.is_valid('PT10M21.S')) self.assertFalse(day_time_duration_type.is_valid('P')) self.assertFalse(day_time_duration_type.is_valid('')) def test_year_month_duration_type(self): year_month_duration_type = self.types['yearMonthDuration'] self.assertTrue(year_month_duration_type.is_valid('P3Y4M')) self.assertTrue(year_month_duration_type.is_valid('P15M')) self.assertTrue(year_month_duration_type.is_valid('P0Y')) self.assertTrue(year_month_duration_type.is_valid('P0Y23M')) self.assertTrue(year_month_duration_type.is_valid('-P8Y')) self.assertFalse(year_month_duration_type.is_valid('3Y4M')) self.assertFalse(year_month_duration_type.is_valid('P6M1Y')) self.assertFalse(year_month_duration_type.is_valid('P')) self.assertFalse(year_month_duration_type.is_valid('P1Y6M15D')) self.assertFalse(year_month_duration_type.is_valid('P1.2Y')) self.assertFalse(year_month_duration_type.is_valid('P2YM')) self.assertFalse(year_month_duration_type.is_valid('P-1Y')) self.assertFalse(year_month_duration_type.is_valid('')) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD builtins with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_complex_types.py���������������������������������������������0000664�0000000�0000000�00000050206�14211403446�0023372�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import warnings from xmlschema import XMLSchemaParseError, XMLSchemaModelError from xmlschema.etree import etree_element from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase class TestXsdComplexType(XsdValidatorTestCase): def check_complex_restriction(self, base, restriction, expected=None, **kwargs): content = 'complex' if self.content_pattern.search(base) else 'simple' source = """ <xs:complexType name="targetType"> {0} </xs:complexType> <xs:complexType name="restrictedType"> <xs:{1}Content> <xs:restriction base="targetType"> {2} </xs:restriction> </xs:{1}Content> </xs:complexType> """.format(base.strip(), content, restriction.strip()) self.check_schema(source, expected, **kwargs) def test_element_restrictions(self): base = """ <xs:sequence> <xs:element name="A" maxOccurs="7"/> <xs:element name="B" type="xs:string"/> <xs:element name="C" fixed="5"/> </xs:sequence> """ self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A" maxOccurs="6"/> <xs:element name="B" type="xs:NCName"/> <xs:element name="C" fixed="5"/> </xs:sequence> """ ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A" maxOccurs="8"/> <!-- <<< More occurrences --> <xs:element name="B" type="xs:NCName"/> <xs:element name="C" fixed="5"/> </xs:sequence> """, expected=XMLSchemaParseError ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A" maxOccurs="6"/> <xs:element name="B" type="float"/> <!-- <<< Not a derived type --> <xs:element name="C" fixed="5"/> </xs:sequence> """, expected=XMLSchemaParseError ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A" maxOccurs="6"/> <xs:element name="B" type="xs:NCName"/> <xs:element name="C" fixed="3"/> <!-- <<< Different fixed value --> </xs:sequence> """, expected=XMLSchemaParseError ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A" maxOccurs="6" nillable="true"/> <!-- <<< nillable is True --> <xs:element name="B" type="xs:NCName"/> <xs:element name="C" fixed="5"/> </xs:sequence> """, expected=XMLSchemaParseError ) def test_sequence_group_restriction(self): # Meaningless sequence group base = """ <xs:sequence> <xs:sequence> <xs:element name="A"/> <xs:element name="B"/> </xs:sequence> </xs:sequence> """ self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A"/> <xs:element name="B"/> </xs:sequence> """ ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A"/> <xs:element name="C"/> </xs:sequence> """, expected=XMLSchemaParseError ) base = """ <xs:sequence> <xs:element name="A"/> <xs:element name="B" minOccurs="0"/> </xs:sequence> """ self.check_complex_restriction(base, '<xs:sequence><xs:element name="A"/></xs:sequence>') self.check_complex_restriction( base, '<xs:sequence><xs:element name="B"/></xs:sequence>', XMLSchemaParseError ) self.check_complex_restriction( base, '<xs:sequence><xs:element name="C"/></xs:sequence>', XMLSchemaParseError ) self.check_complex_restriction( base, '<xs:sequence><xs:element name="A"/><xs:element name="B"/></xs:sequence>' ) self.check_complex_restriction( base, '<xs:sequence><xs:element name="A"/><xs:element name="C"/></xs:sequence>', XMLSchemaParseError ) self.check_complex_restriction( base, '<xs:sequence><xs:element name="A" minOccurs="0"/><xs:element name="B"/></xs:sequence>', XMLSchemaParseError ) self.check_complex_restriction( base, '<xs:sequence><xs:element name="B" minOccurs="0"/><xs:element name="A"/></xs:sequence>', XMLSchemaParseError ) def test_all_group_restriction(self): base = """ <xs:all> <xs:element name="A"/> <xs:element name="B" minOccurs="0"/> <xs:element name="C" minOccurs="0"/> </xs:all> """ self.check_complex_restriction( base, restriction=""" <xs:all> <xs:element name="A"/> <xs:element name="C"/> </xs:all> """) self.check_complex_restriction( base, restriction=""" <xs:all> <xs:element name="C" minOccurs="0"/> <xs:element name="A"/> </xs:all> """, expected=XMLSchemaParseError if self.schema_class.XSD_VERSION == '1.0' else None ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A"/> <xs:element name="C"/> </xs:sequence> """) self.check_complex_restriction( base, '<xs:sequence><xs:element name="C" minOccurs="0"/><xs:element name="A"/></xs:sequence>' ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="C" minOccurs="0"/> <xs:element name="A" minOccurs="0"/> </xs:sequence> """, expected=XMLSchemaParseError ) self.check_complex_restriction( base, restriction=""" <xs:sequence> <xs:element name="A"/> <xs:element name="X"/> </xs:sequence> """, expected=XMLSchemaParseError ) base = """ <xs:all> <xs:element name="A" minOccurs="0" maxOccurs="0"/> </xs:all> """ self.check_complex_restriction(base, '<xs:all><xs:element name="A"/></xs:all>', XMLSchemaParseError) def test_choice_group_restriction(self): base = """ <xs:choice maxOccurs="2"> <xs:element name="A"/> <xs:element name="B"/> <xs:element name="C"/> </xs:choice> """ self.check_complex_restriction( base, '<xs:choice><xs:element name="A"/><xs:element name="C"/></xs:choice>') self.check_complex_restriction( base, '<xs:choice maxOccurs="2"><xs:element name="C"/><xs:element name="A"/></xs:choice>', XMLSchemaParseError if self.schema_class.XSD_VERSION == '1.0' else None ) self.check_complex_restriction( base, '<xs:choice maxOccurs="2"><xs:element name="A"/><xs:element name="C"/></xs:choice>', ) def test_occurs_restriction(self): base = """ <xs:sequence minOccurs="3" maxOccurs="10"> <xs:element name="A"/> </xs:sequence> """ self.check_complex_restriction( base, '<xs:sequence minOccurs="3" maxOccurs="7"><xs:element name="A"/></xs:sequence>') self.check_complex_restriction( base, '<xs:sequence minOccurs="4" maxOccurs="10"><xs:element name="A"/></xs:sequence>') self.check_complex_restriction( base, '<xs:sequence minOccurs="3" maxOccurs="11"><xs:element name="A"/></xs:sequence>', XMLSchemaParseError ) self.check_complex_restriction( base, '<xs:sequence minOccurs="2" maxOccurs="10"><xs:element name="A"/></xs:sequence>', XMLSchemaParseError ) def test_recursive_complex_type(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elemA" type="typeA"/> <xs:complexType name="typeA"> <xs:sequence> <xs:element ref="elemA" minOccurs="0" maxOccurs="5"/> </xs:sequence> </xs:complexType> </xs:schema>""") self.assertEqual(schema.elements['elemA'].type, schema.types['typeA']) def test_upa_violations(self): self.check_schema(""" <xs:complexType name="typeA"> <xs:sequence> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="A"/> <xs:element name="B"/> </xs:sequence> <xs:element name="A" minOccurs="0"/> </xs:sequence> </xs:complexType>""", XMLSchemaModelError) self.check_schema(""" <xs:complexType name="typeA"> <xs:sequence> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="B"/> <xs:element name="A"/> </xs:sequence> <xs:element name="A" minOccurs="0"/> </xs:sequence> </xs:complexType>""") def test_upa_violation_with_wildcard(self): self.check_schema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns" xmlns:ns="tns" elementFormDefault="unqualified"> <xs:complexType name="baseType"> <xs:sequence> <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"></xs:any> </xs:sequence> </xs:complexType> <xs:complexType name="addressType"> <xs:complexContent> <xs:extension base="ns:baseType"> <xs:sequence> <xs:element name="state" type="xs:string" /> <xs:element name="currency" type="xs:string" /> <xs:element name="zip" type="xs:int" /> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema> """, XMLSchemaModelError if self.schema_class.XSD_VERSION == '1.0' else None) def test_content_type(self): # Ref: https://www.w3.org/TR/xmlschema11-1/#Complex_Type_Definition_details schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="emptyContentType1"> <xs:attribute name="a1"/> </xs:complexType> <xs:simpleType name="emptyContentType2"> <xs:restriction base="xs:string"> <xs:length value="0"/> </xs:restriction> </xs:simpleType> <xs:complexType name="emptyContentType3"> <xs:simpleContent> <xs:extension base="emptyContentType2"> <xs:attribute name="a1"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:simpleType name="simpleContentType1"> <xs:restriction base="xs:string"> <xs:length value="1"/> </xs:restriction> </xs:simpleType> <xs:complexType name="simpleContentType2"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="a1"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:complexType name="elementOnlyContentType"> <xs:sequence> <xs:element name="elem1"/> </xs:sequence> </xs:complexType> <xs:complexType name="mixedContentType" mixed="true"> <xs:sequence> <xs:element name="elem1"/> </xs:sequence> </xs:complexType> </xs:schema> """) xsd_type = schema.types['emptyContentType1'] self.assertTrue(xsd_type.is_empty()) self.assertFalse(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'empty') xsd_type = schema.types['emptyContentType2'] self.assertTrue(xsd_type.is_empty()) self.assertFalse(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'empty') xsd_type = schema.types['emptyContentType3'] self.assertTrue(xsd_type.is_empty()) self.assertFalse(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'empty') xsd_type = schema.types['simpleContentType1'] self.assertFalse(xsd_type.is_empty()) self.assertTrue(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'simple') xsd_type = schema.types['simpleContentType2'] self.assertFalse(xsd_type.is_empty()) self.assertTrue(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'simple') xsd_type = schema.types['elementOnlyContentType'] self.assertFalse(xsd_type.is_empty()) self.assertFalse(xsd_type.has_simple_content()) self.assertTrue(xsd_type.is_element_only()) self.assertFalse(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'element-only') xsd_type = schema.types['mixedContentType'] self.assertFalse(xsd_type.is_empty()) self.assertFalse(xsd_type.has_simple_content()) self.assertFalse(xsd_type.is_element_only()) self.assertTrue(xsd_type.has_mixed_content()) self.assertEqual(xsd_type.content_type_label, 'mixed') def test_content_type_property(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="type1"> <xs:sequence> <xs:element name="elem1"/> </xs:sequence> </xs:complexType> </xs:schema>""") xsd_type = schema.types['type1'] with warnings.catch_warnings(record=True) as context: warnings.simplefilter("always") self.assertIs(xsd_type.content_type, xsd_type.content) self.assertEqual(len(context), 1) self.assertIs(context[0].category, DeprecationWarning) def test_is_empty(self): schema = self.check_schema(""" <xs:complexType name="emptyType1"/> <xs:complexType name="emptyType2"> <xs:sequence/> </xs:complexType> <xs:complexType name="emptyType3"> <xs:complexContent> <xs:restriction base="xs:anyType"/> </xs:complexContent> </xs:complexType> <xs:complexType name="notEmptyType1"> <xs:sequence> <xs:element name="elem1"/> </xs:sequence> </xs:complexType> <xs:complexType name="notEmptyType2"> <xs:complexContent> <xs:extension base="xs:anyType"/> </xs:complexContent> </xs:complexType> """) self.assertTrue(schema.types['emptyType1'].is_empty()) self.assertTrue(schema.types['emptyType2'].is_empty()) self.assertTrue(schema.types['emptyType3'].is_empty()) self.assertFalse(schema.types['notEmptyType1'].is_empty()) self.assertFalse(schema.types['notEmptyType2'].is_empty()) class TestXsd11ComplexType(TestXsdComplexType): schema_class = XMLSchema11 def test_complex_type_assertion(self): schema = self.check_schema(""" <xs:complexType name="intRange"> <xs:attribute name="min" type="xs:int"/> <xs:attribute name="max" type="xs:int"/> <xs:assert test="@min le @max"/> </xs:complexType>""") xsd_type = schema.types['intRange'] xsd_type.decode(etree_element('a', attrib={'min': '10', 'max': '19'})) self.assertTrue(xsd_type.is_valid(etree_element('a', attrib={'min': '10', 'max': '19'}))) self.assertTrue(xsd_type.is_valid(etree_element('a', attrib={'min': '19', 'max': '19'}))) self.assertFalse(xsd_type.is_valid(etree_element('a', attrib={'min': '25', 'max': '19'}))) self.assertTrue(xsd_type.is_valid(etree_element('a', attrib={'min': '25', 'max': '100'}))) def test_sequence_extension(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="base"> <xs:openContent mode="suffix"> <xs:any namespace="tns1" processContents="lax"/> </xs:openContent> <xs:sequence> <xs:element name="a" maxOccurs="unbounded"/> <xs:element name="b" minOccurs="0"/> <xs:element name="c" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="ext"> <xs:complexContent> <xs:extension base="base"> <xs:sequence> <xs:element name="d" minOccurs="0"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema>""") base_group = schema.types['base'].content self.assertEqual(base_group.model, 'sequence') self.assertEqual(base_group[0].name, 'a') self.assertEqual(base_group[1].name, 'b') self.assertEqual(base_group[2].name, 'c') self.assertEqual(len(base_group), 3) ext_group = schema.types['ext'].content self.assertEqual(ext_group.model, 'sequence') self.assertEqual(len(ext_group), 2) self.assertEqual(ext_group[0].model, 'sequence') self.assertEqual(ext_group[1].model, 'sequence') self.assertEqual(ext_group[0][0].name, 'a') self.assertEqual(ext_group[0][1].name, 'b') self.assertEqual(ext_group[0][2].name, 'c') self.assertEqual(len(ext_group[0]), 3) self.assertEqual(ext_group[1][0].name, 'd') self.assertEqual(len(ext_group[1]), 1) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD complex types with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_elements.py��������������������������������������������������0000664�0000000�0000000�00000011552�14211403446�0022314�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchemaParseError from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase class TestXsdElements(XsdValidatorTestCase): def test_element_ref(self): schema = self.check_schema(""" <xs:element name="node" type="xs:string"/> <xs:group name="group"> <xs:sequence> <xs:element ref="node"/> </xs:sequence> </xs:group>""") self.assertIs(schema.elements['node'].type, schema.groups['group'][0].type) self.check_schema(""" <xs:element name="node" type="xs:string"/> <xs:group name="group"> <xs:sequence> <xs:element ref="unknown"/> </xs:sequence> </xs:group>""", XMLSchemaParseError) self.check_schema(""" <xs:element name="node" type="xs:string"/> <xs:group name="group"> <xs:sequence> <xs:element ref="node" default="foo"/> </xs:sequence> </xs:group>""", XMLSchemaParseError) def test_name_attribute(self): schema = self.check_schema(""" <xs:group name="group"> <xs:sequence> <xs:element/> </xs:sequence> </xs:group>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) def test_form_attribute(self): schema = self.check_schema(""" <xs:group name="group"> <xs:sequence> <xs:element name="elem1" form="qualified"/> <xs:element name="elem2" form="unqualified"/> </xs:sequence> </xs:group>""") self.assertTrue(schema.groups['group'][0].qualified) self.assertFalse(schema.groups['group'][1].qualified) def test_nillable_attribute(self): schema = self.check_schema(""" <xs:group name="group"> <xs:sequence> <xs:element name="elem1" nillable=" true "/> <xs:element name="elem2" nillable=" false "/> <xs:element name="elem3" nillable=" True "/> </xs:sequence> </xs:group>""", validation='lax') self.assertTrue(schema.groups['group'][0].nillable) self.assertFalse(schema.groups['group'][1].nillable) self.assertFalse(schema.groups['group'][2].nillable) self.assertEqual(len(schema.all_errors), 1) self.assertIn("'True' is not a boolean value", schema.all_errors[0].message) def test_scope_property(self): schema = self.check_schema(""" <xs:element name="global_elem" type="xs:string"/> <xs:group name="group"> <xs:sequence> <xs:element name="local_elem" type="xs:string"/> </xs:sequence> </xs:group> """) self.assertEqual(schema.elements['global_elem'].scope, 'global') self.assertEqual(schema.groups['group'][0].scope, 'local') def test_value_constraint_property(self): schema = self.check_schema(""" <xs:group name="group"> <xs:sequence> <xs:element name="elem1" type="xs:string"/> <xs:element name="elem2" type="xs:string" default="alpha"/> <xs:element name="elem3" type="xs:string" default="beta"/> </xs:sequence> </xs:group> """) model_group = schema.groups['group'] self.assertIsNone(model_group[0].value_constraint) self.assertEqual(model_group[1].value_constraint, 'alpha') self.assertEqual(model_group[2].value_constraint, 'beta') def test_is_empty_attribute(self): schema = self.check_schema(""" <xs:element name="e1" type="xs:string"/> <xs:element name="e2" type="xs:string" fixed=""/> <xs:element name="e3" type="emptyString"/> <xs:simpleType name="emptyString"> <xs:restriction base="xs:string"> <xs:maxLength value="0"/> </xs:restriction> </xs:simpleType> """) self.assertFalse(schema.elements['e1'].is_empty()) self.assertTrue(schema.elements['e2'].is_empty()) self.assertTrue(schema.elements['e3'].is_empty()) class TestXsd11Elements(TestXsdElements): schema_class = XMLSchema11 if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD elements with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_exceptions.py������������������������������������������������0000664�0000000�0000000�00000022400�14211403446�0022653�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import io try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema import XMLSchema, XMLResource from xmlschema.etree import ElementTree from xmlschema.validators.exceptions import XMLSchemaValidatorError, \ XMLSchemaNotBuiltError, XMLSchemaModelDepthError, XMLSchemaValidationError, \ XMLSchemaChildrenValidationError CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') class TestValidatorExceptions(unittest.TestCase): def test_exception_init(self): xs = XMLSchema(os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd')) with self.assertRaises(ValueError) as ctx: XMLSchemaValidatorError(xs, 'unknown error', elem='wrong') self.assertIn("'elem' attribute requires an Element", str(ctx.exception)) error = XMLSchemaNotBuiltError(xs, 'schema not built!') self.assertEqual(error.message, 'schema not built!') schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:group name="group1"> <xs:choice> <xs:element name="root" type="xs:integer"/> </xs:choice> </xs:group> </xs:schema>""") error = XMLSchemaModelDepthError(schema.groups['group1']) self.assertEqual("maximum model recursion depth exceeded", error.message[:38]) def test_exception_repr(self): xs = XMLSchema(os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd')) error = XMLSchemaValidatorError(xs, 'unknown error') self.assertEqual(str(error), 'unknown error') self.assertEqual(error.msg, 'unknown error') error = XMLSchemaValidatorError(xs, 'unknown error', elem=xs.root) output = str(error) lines = output.split('\n') self.assertGreater(len(lines), 10, msg=output) self.assertEqual(lines[0], 'unknown error:', msg=output) self.assertEqual(lines[2], 'Schema:', msg=output) self.assertRegex(lines[4].strip(), '^<(xs:)?schema ', msg=output) self.assertRegex(lines[-2].strip(), '</(xs:|xsd:)?schema>$', msg=output) @unittest.skipIf(lxml_etree is None, 'lxml is not installed ...') def test_exception_repr_lxml(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:integer"/> </xs:schema>""") root = lxml_etree.XML('<root a="10"/>') with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate(root) lines = str(ctx.exception).split('\n') self.assertEqual(lines[0], "failed validating {'a': '10'} with XsdAttributeGroup():") self.assertEqual(lines[2], "Reason: 'a' attribute not allowed for element.") self.assertEqual(lines[8], "Instance (line 1):") self.assertEqual(lines[12], "Path: /root") self.assertEqual(repr(ctx.exception), "XMLSchemaValidationError(reason=\"'a' " "attribute not allowed for element.\")") error = XMLSchemaValidationError(schema.elements['root'], root) self.assertIsNone(error.reason) self.assertNotIn("Reason:", str(error)) self.assertIn("Schema:", str(error)) error = XMLSchemaValidationError(schema, root) self.assertNotIn("Reason:", str(error)) self.assertNotIn("Schema:", str(error)) error = XMLSchemaValidationError(schema, 10) self.assertEqual(str(error), "failed validating 10 with XMLSchema10(namespace='')") def test_setattr(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:integer"/> </xs:schema>""") root = ElementTree.XML('<root a="10"/>') with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate(root) self.assertIsInstance(ctx.exception.source, XMLResource) self.assertFalse(ctx.exception.source.is_lazy()) resource = XMLResource(io.StringIO('<root a="10"/>'), lazy=True) with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate(resource) self.assertIsInstance(ctx.exception.source, XMLResource) self.assertTrue(ctx.exception.source.is_lazy()) self.assertIsNone(ctx.exception.elem) self.assertEqual(ctx.exception.source, resource) self.assertEqual(ctx.exception.path, '/root') @unittest.skipIf(lxml_etree is None, 'lxml is not installed ...') def test_sourceline_property(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:integer"/> </xs:schema>""") root = lxml_etree.XML('<root a="10"/>') with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate(root) self.assertEqual(ctx.exception.sourceline, 1) self.assertEqual(ctx.exception.root, root) def test_other_properties(self): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') xs = XMLSchema(xsd_file) with self.assertRaises(XMLSchemaValidatorError) as ctx: raise XMLSchemaValidatorError(xs, 'unknown error') self.assertIsNone(ctx.exception.root) self.assertIsNone(ctx.exception.schema_url) self.assertEqual(ctx.exception.origin_url, xs.source.url) self.assertIsNone(XMLSchemaValidatorError(None, 'unknown error').origin_url) def test_children_validation_error(self): schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="a"> <xs:complexType> <xs:sequence> <xs:element name="b1" type="xs:string"/> <xs:element name="b2" type="xs:string"/> <xs:element name="b3" type="xs:string" minOccurs="2" maxOccurs="3"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") with self.assertRaises(XMLSchemaChildrenValidationError) as ctx: schema.validate('<a><b1/><b2/><b3/><b3/><b3/><b3/></a>') lines = str(ctx.exception).split('\n') self.assertEqual(lines[2], "Reason: Unexpected child with tag 'b3' at position 6.") self.assertEqual(lines[-2], "Path: /a") with self.assertRaises(XMLSchemaChildrenValidationError) as ctx: schema.validate('<a><b1/><b2/><b3/></a>') lines = str(ctx.exception).split('\n') self.assertEqual(lines[2][:51], "Reason: The content of element 'a' is not complete.") self.assertEqual(lines[-2], "Path: /a") root = ElementTree.XML('<a><b1/><b2/><b2/><b3/><b3/><b3/></a>') validator = schema.elements['a'].type.content with self.assertRaises(XMLSchemaChildrenValidationError) as ctx: raise XMLSchemaChildrenValidationError(validator, root, 2, validator[1], 2) lines = str(ctx.exception).split('\n') self.assertTrue(lines[2].endswith("occurs 2 times but the maximum is 1.")) schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="a"> <xs:complexType> <xs:sequence> <xs:element name="b1" type="xs:string"/> <xs:any/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") with self.assertRaises(XMLSchemaChildrenValidationError) as ctx: schema.validate('<a><b1/></a>') lines = str(ctx.exception).split('\n') self.assertTrue(lines[2].endswith("Tag from \'##any\' namespace/s expected.")) schema = XMLSchema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="a"> <xs:complexType> <xs:sequence> <xs:element name="b1" type="xs:string"/> <xs:choice> <xs:any namespace="tns0" processContents="lax"/> <xs:element name="b2" type="xs:string"/> </xs:choice> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") with self.assertRaises(XMLSchemaChildrenValidationError) as ctx: schema.validate('<a><b1/></a>') lines = str(ctx.exception).split('\n') self.assertTrue(lines[2].endswith("Tag 'b2' expected.")) if __name__ == '__main__': import platform header_template = "Test xmlschema's validator exceptions with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_facets.py����������������������������������������������������0000664�0000000�0000000�00000165403�14211403446�0021752�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import decimal import pathlib from xml.etree import ElementTree from textwrap import dedent from xmlschema import XMLSchema10, XMLSchema11, XMLSchemaValidationError, \ XMLSchemaParseError from xmlschema.names import XSD_NAMESPACE, XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, \ XSD_WHITE_SPACE, XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_MAX_INCLUSIVE, \ XSD_MAX_EXCLUSIVE, XSD_TOTAL_DIGITS, XSD_FRACTION_DIGITS, XSD_ENUMERATION, \ XSD_PATTERN, XSD_ASSERTION class TestXsdFacets(unittest.TestCase): schema_class = XMLSchema10 @classmethod def setUpClass(cls): cls.st_xsd_file = pathlib.Path(__file__).absolute().parent.parent.joinpath( 'test_cases/features/decoder/simple-types.xsd' ) cls.st_schema = cls.schema_class(cls.st_xsd_file.as_uri()) def test_white_space_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:whiteSpace value="preserve"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string2"> <xs:restriction base="xs:string"> <xs:whiteSpace value="replace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string3"> <xs:restriction base="xs:string"> <xs:whiteSpace value="collapse"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) xsd_type = schema.types['string1'] self.assertEqual(xsd_type.white_space, 'preserve') white_space_facet = xsd_type.get_facet(XSD_WHITE_SPACE) self.assertIsNone(white_space_facet(' \t alpha\n beta ')) xsd_type = schema.types['string2'] self.assertEqual(xsd_type.white_space, 'replace') white_space_facet = xsd_type.get_facet(XSD_WHITE_SPACE) self.assertIsNone(white_space_facet(' alpha beta ')) with self.assertRaises(XMLSchemaValidationError) as ec: white_space_facet(' \t alpha\n beta ') self.assertIn('Reason: value contains tabs or newlines', str(ec.exception)) xsd_type = schema.types['string3'] self.assertEqual(xsd_type.white_space, 'collapse') white_space_facet = xsd_type.get_facet(XSD_WHITE_SPACE) self.assertIsNone(white_space_facet('alpha beta')) with self.assertRaises(XMLSchemaValidationError) as ec: white_space_facet(' alpha beta ') self.assertIn('Reason: value contains non collapsed white spaces', str(ec.exception)) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:whiteSpace value="invalid"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn( "value must be one of ['preserve', 'replace', 'collapse']", str(ec.exception) ) def test_white_space_restriction(self): valid_derivations = [ ('preserve', 'preserve'), ('preserve', 'replace'), ('preserve', 'collapse'), ('replace', 'replace'), ('replace', 'collapse'), ('collapse', 'collapse'), ] for base_value, value in valid_derivations: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:whiteSpace value="{base_value}"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string2"> <xs:restriction base="string1"> <xs:whiteSpace value="{value}"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertEqual(schema.types['string1'].white_space, base_value) self.assertEqual(schema.types['string2'].white_space, value) invalid_derivations = [ ('replace', 'preserve'), ('collapse', 'preserve'), ('collapse', 'replace') ] for base_value, value in invalid_derivations: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:whiteSpace value="{base_value}"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string2"> <xs:restriction base="string1"> <xs:whiteSpace value="{value}"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_length_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="username"> <xs:restriction base="xs:NCName"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) length_facet = schema.types['username'].get_facet(XSD_LENGTH) self.assertIsNone(length_facet('a' * 8)) for value in ['', 'a' * 7, 'a' * 9]: with self.assertRaises(XMLSchemaValidationError) as ec: length_facet(value) self.assertIn('Reason: length has to be 8', str(ec.exception)) def test_length_facet_restriction(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="username"> <xs:restriction base="xs:NCName"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="username2"> <xs:restriction base="username"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) length_facet = schema.types['username'].get_facet(XSD_LENGTH) self.assertIsNone(length_facet('a' * 8)) length_facet2 = schema.types['username2'].get_facet(XSD_LENGTH) self.assertIsNone(length_facet2('a' * 8)) self.assertIsNot(length_facet, length_facet2) # Not applied on xs:QName: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="qname1"> <xs:restriction base="xs:QName"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) length_facet = schema.types['qname1'].get_facet(XSD_LENGTH) self.assertIsNone(length_facet('a' * 8)) self.assertIsNone(length_facet('a' * 10)) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="username"> <xs:restriction base="xs:NCName"> <xs:length value="8"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="username2"> <xs:restriction base="username"> <xs:length value="12"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("base facet has a different length (8)", str(ec.exception)) def test_min_length_facet(self): xsd_type = self.st_schema.types['none_empty_string'] min_length_facet = xsd_type.get_facet(XSD_MIN_LENGTH) self.assertIsNone(min_length_facet(' ')) self.assertIsNone(min_length_facet(' ' * 75)) with self.assertRaises(XMLSchemaValidationError) as ec: min_length_facet('') self.assertIn('value length cannot be lesser than 1', str(ec.exception)) # Not applied on xs:QName: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="qname1"> <xs:restriction base="xs:QName"> <xs:minLength value="8"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) min_length_facet = schema.types['qname1'].get_facet(XSD_MIN_LENGTH) self.assertIsNone(min_length_facet('abc')) def test_min_length_facet_restriction(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string20"> <xs:restriction base="xs:string"> <xs:minLength value="20"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string30"> <xs:restriction base="string20"> <xs:minLength value="30"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertEqual(schema.types['string20'].get_facet(XSD_MIN_LENGTH).value, 20) self.assertEqual(schema.types['string30'].get_facet(XSD_MIN_LENGTH).value, 30) with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string40"> <xs:restriction base="xs:string"> <xs:minLength value="40"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string30"> <xs:restriction base="string40"> <xs:minLength value="30"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_max_length_facet(self): xsd_type = self.st_schema.types['string_75'] max_length_facet = xsd_type.get_facet(XSD_MAX_LENGTH) self.assertIsNone(max_length_facet('')) self.assertIsNone(max_length_facet(' ')) self.assertIsNone(max_length_facet(' ' * 75)) with self.assertRaises(XMLSchemaValidationError) as ec: max_length_facet(' ' * 76) self.assertIn('value length cannot be greater than 75', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError) as ec: max_length_facet(None) self.assertIn("invalid type <class 'NoneType'> provided", str(ec.exception)) # Not applied on xs:QName: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="qname1"> <xs:restriction base="xs:QName"> <xs:maxLength value="8"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) max_length_facet = schema.types['qname1'].get_facet(XSD_MAX_LENGTH) self.assertIsNone(max_length_facet('a' * 10)) def test_max_length_facet_restriction(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string30"> <xs:restriction base="xs:string"> <xs:maxLength value="30"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string20"> <xs:restriction base="string30"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertEqual(schema.types['string30'].get_facet(XSD_MAX_LENGTH).value, 30) self.assertEqual(schema.types['string20'].get_facet(XSD_MAX_LENGTH).value, 20) with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string30"> <xs:restriction base="xs:string"> <xs:maxLength value="30"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string40"> <xs:restriction base="string30"> <xs:maxLength value="40"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_min_inclusive_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['min_type'].get_facet(XSD_MIN_INCLUSIVE) self.assertIsNone(facet(0)) self.assertIsNone(facet(100)) with self.assertRaises(XMLSchemaValidationError) as ec: facet(-1) self.assertIn('value has to be greater or equal than 0', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet('') with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:minInclusive value=""/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_min_inclusive_facet_restriction(self): for base_facet in ['minInclusive', 'maxInclusive']: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['type1'].get_facet('{%s}%s' % (XSD_NAMESPACE, base_facet)) self.assertIsNone(facet(0)) facet2 = schema.types['type2'].get_facet(XSD_MIN_INCLUSIVE) self.assertIsNone(facet2(0)) self.assertIsNot(facet, facet2) for base_facet in ['minInclusive', 'minExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['maxInclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="-1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['minExclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_min_exclusive_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:minExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['min_type'].get_facet(XSD_MIN_EXCLUSIVE) self.assertIsNone(facet(1)) with self.assertRaises(XMLSchemaValidationError) as ec: facet(0) self.assertIn('value has to be greater than 0', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet('') with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:minExclusive value=""/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_min_exclusive_facet_restriction(self): for base_facet in ['minInclusive', 'minExclusive']: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['type1'].get_facet('{%s}%s' % (XSD_NAMESPACE, base_facet)) self.assertIsNone(facet(1)) facet2 = schema.types['type2'].get_facet(XSD_MIN_EXCLUSIVE) self.assertIsNone(facet2(1)) self.assertIsNot(facet, facet2) for base_facet in ['maxInclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['minInclusive', 'minExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['maxInclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="-1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:minExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_max_inclusive_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="max_type"> <xs:restriction base="xs:integer"> <xs:maxInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['max_type'].get_facet(XSD_MAX_INCLUSIVE) self.assertIsNone(facet(-1)) self.assertIsNone(facet(0)) with self.assertRaises(XMLSchemaValidationError) as ec: facet(1) self.assertIn('value has to be lesser or equal than 0', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet('') with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:maxInclusive value=""/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_max_inclusive_facet_restriction(self): for base_facet in ['minInclusive', 'maxInclusive']: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['type1'].get_facet('{%s}%s' % (XSD_NAMESPACE, base_facet)) self.assertIsNone(facet(0)) facet2 = schema.types['type2'].get_facet(XSD_MAX_INCLUSIVE) self.assertIsNone(facet2(0)) self.assertIsNot(facet, facet2) for base_facet in ['maxInclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="-1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['minInclusive', 'minExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['minExclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxInclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_max_exclusive_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="max_type"> <xs:restriction base="xs:integer"> <xs:maxExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['max_type'].get_facet(XSD_MAX_EXCLUSIVE) self.assertIsNone(facet(-1)) with self.assertRaises(XMLSchemaValidationError) as ec: facet(0) self.assertIn('value has to be lesser than 0', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet('') with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="min_type"> <xs:restriction base="xs:integer"> <xs:maxExclusive value=""/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_max_exclusive_facet_restriction(self): for base_facet in ['maxInclusive', 'maxExclusive']: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['type1'].get_facet('{%s}%s' % (XSD_NAMESPACE, base_facet)) self.assertIsNone(facet(-1)) facet2 = schema.types['type2'].get_facet(XSD_MAX_EXCLUSIVE) self.assertIsNone(facet2(-1)) self.assertIsNot(facet, facet2) for base_facet in ['minInclusive', 'minExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['maxInclusive', 'maxExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="-1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) for base_facet in ['minInclusive', 'minExclusive']: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="type1"> <xs:restriction base="xs:integer"> <xs:{base_facet} value="1"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="type2"> <xs:restriction base="type1"> <xs:maxExclusive value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_total_digits_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_integer"> <xs:restriction base="xs:integer"> <xs:totalDigits value="4"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['restricted_integer'].get_facet(XSD_TOTAL_DIGITS) self.assertIsNone(facet(9999)) with self.assertRaises(XMLSchemaValidationError) as ec: facet(99999) self.assertIn('the number of digits has to be lesser or equal than 4', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet(None) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_integer"> <xs:restriction base="xs:integer"> <xs:totalDigits value="a"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertIn("invalid literal", str(schema.all_errors[0])) facet = schema.types['restricted_integer'].get_facet(XSD_TOTAL_DIGITS) self.assertEqual(facet.value, 9999) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_integer"> <xs:restriction base="xs:integer"> <xs:totalDigits value="0"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertIn("value must be positive", str(schema.all_errors[0])) facet = schema.types['restricted_integer'].get_facet(XSD_TOTAL_DIGITS) self.assertEqual(facet.value, 9999) def test_fraction_digits_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_decimal"> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="2"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['restricted_decimal'].get_facet(XSD_FRACTION_DIGITS) self.assertIsNone(facet(decimal.Decimal('99.99'))) with self.assertRaises(XMLSchemaValidationError) as ec: facet(decimal.Decimal('99.999')) self.assertIn('fraction digits has to be lesser or equal than 2', str(ec.exception)) with self.assertRaises(XMLSchemaValidationError): facet(None) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_decimal"> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="a"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertIn("invalid literal", str(schema.all_errors[0])) facet = schema.types['restricted_decimal'].get_facet(XSD_FRACTION_DIGITS) self.assertEqual(facet.value, 9999) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_decimal"> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="-1"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertIn("value must be non negative", str(schema.all_errors[0])) facet = schema.types['restricted_decimal'].get_facet(XSD_FRACTION_DIGITS) self.assertEqual(facet.value, 9999) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_integer"> <xs:restriction base="xs:integer"> <xs:fractionDigits value="2"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("value has to be 0 for types derived from xs:integer", str(ec.exception)) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="restricted_double"> <xs:restriction base="xs:double"> <xs:fractionDigits value="2"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("can be applied only to types derived from xs:decimal", str(ec.exception)) def test_digits_facets_restriction(self): for facet in ['totalDigits', 'fractionDigits']: schema = self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="decimal1"> <xs:restriction base="xs:decimal"> <xs:{facet} value="4"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="decimal2"> <xs:restriction base="decimal1"> <xs:{facet} value="1"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertTrue(schema.types['decimal1'].is_valid(decimal.Decimal('.01'))) self.assertFalse(schema.types['decimal2'].is_valid(decimal.Decimal('.01'))) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="decimal1"> <xs:restriction base="xs:decimal"> <xs:{facet} value="2"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="decimal2"> <xs:restriction base="decimal1"> <xs:{facet} value="3"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("invalid restriction: base value is lower", str(ec.exception)) def test_enumeration_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> <xs:enumeration value="three"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="enum2"> <xs:restriction base="enum1"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertTrue(schema.types['enum1'].is_valid('one')) self.assertTrue(schema.types['enum1'].is_valid('two')) self.assertTrue(schema.types['enum1'].is_valid('three')) self.assertFalse(schema.types['enum1'].is_valid('four')) self.assertTrue(schema.types['enum2'].is_valid('one')) self.assertTrue(schema.types['enum2'].is_valid('two')) self.assertFalse(schema.types['enum2'].is_valid('three')) self.assertFalse(schema.types['enum2'].is_valid('four')) facet = schema.types['enum2'].get_facet(XSD_ENUMERATION) elem = ElementTree.Element(XSD_ENUMERATION, value='three') facet.append(elem) self.assertTrue(schema.types['enum2'].is_valid('three')) facet[-1] = elem self.assertTrue(schema.types['enum2'].is_valid('three')) del facet[-1] self.assertFalse(schema.types['enum2'].is_valid('three')) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("missing required attribute 'value'", str(ec.exception)) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:NOTATION"> <xs:enumeration value="unknown:notation1"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("prefix 'unknown' not found in namespace map", str(ec.exception)) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:NOTATION"> <xs:enumeration value="notation1"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("'notation1' must match a notation declaration", str(ec.exception)) def test_enumeration_facet_representation(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> <xs:enumeration value="three"/> <xs:enumeration value="four"/> <xs:enumeration value="five"/> <xs:enumeration value="six"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['enum1'].get_facet(XSD_ENUMERATION) self.assertEqual( repr(facet), "XsdEnumerationFacets(['one', 'two', 'three', 'four', 'five', ...])" ) facet.pop() self.assertEqual( repr(facet), "XsdEnumerationFacets(['one', 'two', 'three', 'four', 'five'])" ) def test_enumeration_facet_with_float_type(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:double"> <xs:enumeration value="1.0"/> <xs:enumeration value="2.0"/> <xs:enumeration value="INF"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['enum1'].get_facet(XSD_ENUMERATION) self.assertIsNone(facet(1.0)) self.assertIsNone(facet(2.0)) self.assertIsNone(facet(float('inf'))) self.assertRaises(XMLSchemaValidationError, facet, '3.0') self.assertRaises(XMLSchemaValidationError, facet, 3.0) self.assertRaises(XMLSchemaValidationError, facet, float('-inf')) self.assertRaises(XMLSchemaValidationError, facet, float('nan')) facet.append(ElementTree.Element(XSD_ENUMERATION, value='-INF')) self.assertIsNone(facet(float('-inf'))) facet.append(ElementTree.Element(XSD_ENUMERATION, value='NaN')) self.assertIsNone(facet(float('nan'))) def test_enumeration_facet_derivation(self): with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="enum2"> <xs:restriction base="enum1"> <xs:enumeration value="one"/> <xs:enumeration value="two"/> <xs:enumeration value="three"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("failed validating 'three'", str(ec.exception)) def test_pattern_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="pattern1"> <xs:restriction base="xs:string"> <xs:pattern value="\\w+"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['pattern1'].get_facet(XSD_PATTERN) self.assertIsNone(facet('abc')) self.assertRaises(XMLSchemaValidationError, facet, '') self.assertRaises(XMLSchemaValidationError, facet, 'a;') self.assertRaises(XMLSchemaValidationError, facet, 10) self.assertRaises(XMLSchemaValidationError, facet, None) self.assertIs(schema.types['pattern1'].patterns, facet) self.assertIs(facet[0], schema.root[0][0][0]) self.assertEqual(facet.patterns[0].pattern, r'^(?:\w+)$(?!\n\Z)') # translated pattern # Test MutableSequence API facet.append(ElementTree.Element(XSD_PATTERN, value=r'\s+')) self.assertEqual(len(facet), 2) self.assertEqual(facet.patterns[1].pattern, r'^(?:\s+)$(?!\n\Z)') facet[1] = (ElementTree.Element(XSD_PATTERN, value=r'\S+')) self.assertEqual(facet.patterns[1].pattern, r'^(?:\S+)$(?!\n\Z)') del facet[1] self.assertEqual(len(facet), 1) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="pattern1"> <xs:restriction base="xs:string"> <xs:pattern/> </xs:restriction> </xs:simpleType> <xs:simpleType name="pattern2"> <xs:restriction base="xs:string"> <xs:pattern value="]"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertEqual(len(schema.all_errors), 2) self.assertIn("missing required attribute 'value'", str(schema.all_errors[0])) self.assertIn("unexpected meta character ']' at position 0", str(schema.all_errors[1])) def test_get_annotation__issue_255(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="enum1"> <xs:restriction base="xs:string"> <xs:enumeration value="one"> <xs:annotation> <xs:documentation>1st facet</xs:documentation> </xs:annotation> </xs:enumeration> <xs:enumeration value="two"/> <xs:enumeration value="three"> <xs:annotation> <xs:documentation>3rd facet</xs:documentation> </xs:annotation> </xs:enumeration> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['enum1'].get_facet(XSD_ENUMERATION) self.assertEqual(facet.annotation.documentation[0].text, '1st facet') self.assertEqual(facet.get_annotation(0).documentation[0].text, '1st facet') self.assertIsNone(facet.get_annotation(1)) self.assertEqual(facet.get_annotation(2).documentation[0].text, '3rd facet') with self.assertRaises(IndexError): facet.get_annotation(3) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="pattern1"> <xs:restriction base="xs:string"> <xs:pattern value="\\w+"/> <xs:pattern value=".+"> <xs:annotation> <xs:documentation>2nd facet</xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['pattern1'].get_facet(XSD_PATTERN) self.assertIsNone(facet.get_annotation(0)) self.assertEqual(facet.get_annotation(1).documentation[0].text, '2nd facet') with self.assertRaises(IndexError): facet.get_annotation(2) def test_fixed_value(self): with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string30"> <xs:restriction base="xs:string"> <xs:maxLength value="30" fixed="true"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string20"> <xs:restriction base="string30"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertIn("'maxLength' facet value is fixed to 30", str(ec.exception)) class TestXsd11Identities(TestXsdFacets): schema_class = XMLSchema11 def test_explicit_timezone_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="date1"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="optional"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date2"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="required"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date3"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="prohibited"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertTrue(schema.types['date1'].is_valid('2020-03-01')) self.assertTrue(schema.types['date2'].is_valid('2020-03-01Z')) self.assertFalse(schema.types['date2'].is_valid('2020-03-01')) self.assertTrue(schema.types['date3'].is_valid('2020-03-01')) self.assertFalse(schema.types['date3'].is_valid('2020-03-01Z')) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="date1"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="none"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertIn("value must be one of ['optional',", str(schema.all_errors[0])) def test_explicit_timezone_facet_restriction(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="date1"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="optional"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date2"> <xs:restriction base="date1"> <xs:explicitTimezone value="required"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date3"> <xs:restriction base="date1"> <xs:explicitTimezone value="prohibited"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date4"> <xs:restriction base="date2"> <xs:explicitTimezone value="required"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date5"> <xs:restriction base="date3"> <xs:explicitTimezone value="prohibited"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) self.assertTrue(schema.types['date1'].is_valid('2020-03-01')) self.assertTrue(schema.types['date2'].is_valid('2020-03-01Z')) self.assertFalse(schema.types['date2'].is_valid('2020-03-01')) self.assertTrue(schema.types['date3'].is_valid('2020-03-01')) self.assertFalse(schema.types['date3'].is_valid('2020-03-01Z')) derivations = [('required', 'prohibited'), ('required', 'optional'), ('prohibited', 'required'), ('prohibited', 'optional')] for base_facet, facet in derivations: with self.assertRaises(XMLSchemaParseError): self.schema_class(dedent(f"""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="date1"> <xs:restriction base="xs:date"> <xs:explicitTimezone value="{base_facet}"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date2"> <xs:restriction base="date1"> <xs:explicitTimezone value="{facet}"/> </xs:restriction> </xs:simpleType> </xs:schema>""")) def test_assertion_facet(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:assertion test="true()"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string2"> <xs:restriction base="xs:string"> <xs:assertion test="last()" xpathDefaultNamespace="http://xpath.test/ns"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="string3"> <xs:restriction base="xs:string"> <xs:assertion test="position()"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="integer_list"> <xs:list itemType="xs:integer"/> </xs:simpleType> <xs:simpleType name="integer_vector"> <xs:restriction base="integer_list"> <xs:assertion test="count($value) eq 3" /> </xs:restriction> </xs:simpleType> </xs:schema>""")) facet = schema.types['string1'].get_facet(XSD_ASSERTION) self.assertIsNone(facet('')) self.assertEqual(facet.xpath_default_namespace, '') facet = schema.types['string2'].get_facet(XSD_ASSERTION) self.assertEqual(facet.xpath_default_namespace, 'http://xpath.test/ns') with self.assertRaises(XMLSchemaValidationError) as ec: facet('') self.assertIn("[err:XPDY0002] context item size is undefined", str(ec.exception)) with self.assertRaises(XMLSchemaValidationError) as ec: schema.types['string3'].get_facet(XSD_ASSERTION)('') self.assertIn("[err:XPDY0002] context item position is undefined", str(ec.exception)) facet = schema.types['integer_vector'].get_facet(XSD_ASSERTION) self.assertIsNone(facet([1, 2, 3])) self.assertEqual(facet.parser.variable_types, {'value': 'xs:anySimpleType'}) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="string1"> <xs:restriction base="xs:string"> <xs:assertion /> </xs:restriction> </xs:simpleType> <xs:simpleType name="string2"> <xs:restriction base="xs:string"> <xs:assertion test="???"/> </xs:restriction> </xs:simpleType> </xs:schema>"""), validation='lax') self.assertEqual(len(schema.all_errors), 2) self.assertIn("missing attribute 'test'", str(schema.all_errors[0])) self.assertIn("[err:XPST0003] unexpected '?' symbol", str(schema.all_errors[1])) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD facets with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_global_maps.py�����������������������������������������������0000664�0000000�0000000�00000012441�14211403446�0022756�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchema10, XMLSchema11 from xmlschema.names import XSD_ELEMENT, XSD_STRING, XSD_SIMPLE_TYPE class TestXsdGlobalsMaps(unittest.TestCase): @classmethod def setUpClass(cls): XMLSchema10.meta_schema.build() XMLSchema11.meta_schema.build() @classmethod def tearDownClass(cls): XMLSchema10.meta_schema.clear() XMLSchema11.meta_schema.clear() def test_maps_repr(self): self.assertEqual( repr(XMLSchema10.meta_schema.maps), "XsdGlobals(validator=MetaXMLSchema10(name='XMLSchema.xsd', " "namespace='http://www.w3.org/2001/XMLSchema'), validation='strict')" ) def test_lookup(self): with self.assertRaises(KeyError): XMLSchema10.meta_schema.maps.lookup(XSD_ELEMENT, 'wrong') xs_string = XMLSchema10.meta_schema.maps.lookup(XSD_SIMPLE_TYPE, XSD_STRING) self.assertEqual(xs_string.name, XSD_STRING) with self.assertRaises(ValueError): XMLSchema10.meta_schema.maps.lookup('simpleType', XSD_STRING) def test_clear(self): maps = XMLSchema10.meta_schema.maps.copy() self.assertEqual(len(list(maps.iter_globals())), 158) maps.clear(only_unbuilt=True) self.assertEqual(len(list(maps.iter_globals())), 158) maps.clear() self.assertEqual(len(list(maps.iter_globals())), 0) maps.build() self.assertEqual(len(list(maps.iter_globals())), 158) maps.clear(remove_schemas=True) self.assertEqual(len(list(maps.iter_globals())), 0) with self.assertRaises(ValueError): maps.build() # missing XSD meta-schema def test_xsd_10_globals(self): self.assertEqual(len(XMLSchema10.meta_schema.maps.notations), 2) self.assertEqual(len(XMLSchema10.meta_schema.maps.types), 92) self.assertEqual(len(XMLSchema10.meta_schema.maps.attributes), 8) self.assertEqual(len(XMLSchema10.meta_schema.maps.attribute_groups), 3) self.assertEqual(len(XMLSchema10.meta_schema.maps.groups), 12) self.assertEqual(len(XMLSchema10.meta_schema.maps.elements), 41) self.assertEqual( len([e.is_global() for e in XMLSchema10.meta_schema.maps.iter_globals()]), 158 ) self.assertEqual(len(XMLSchema10.meta_schema.maps.substitution_groups), 0) def test_xsd_11_globals(self): self.assertEqual(len(XMLSchema11.meta_schema.maps.notations), 2) self.assertEqual(len(XMLSchema11.meta_schema.maps.types), 103) self.assertEqual(len(XMLSchema11.meta_schema.maps.attributes), 14) self.assertEqual(len(XMLSchema11.meta_schema.maps.attribute_groups), 4) self.assertEqual(len(XMLSchema11.meta_schema.maps.groups), 13) self.assertEqual(len(XMLSchema11.meta_schema.maps.elements), 47) self.assertEqual( len([e.is_global() for e in XMLSchema11.meta_schema.maps.iter_globals()]), 183 ) self.assertEqual(len(XMLSchema11.meta_schema.maps.substitution_groups), 1) def test_xsd_10_build(self): self.assertEqual(len([e for e in XMLSchema10.meta_schema.maps.iter_globals()]), 158) self.assertTrue(XMLSchema10.meta_schema.maps.built) XMLSchema10.meta_schema.maps.clear() XMLSchema10.meta_schema.maps.build() self.assertTrue(XMLSchema10.meta_schema.maps.built) def test_xsd_11_build(self): self.assertEqual(len([e for e in XMLSchema11.meta_schema.maps.iter_globals()]), 183) self.assertTrue(XMLSchema11.meta_schema.maps.built) XMLSchema11.meta_schema.maps.clear() XMLSchema11.meta_schema.maps.build() self.assertTrue(XMLSchema11.meta_schema.maps.built) def test_xsd_10_components(self): total_counter = 0 global_counter = 0 for g in XMLSchema10.meta_schema.maps.iter_globals(): for c in g.iter_components(): total_counter += 1 if c.is_global(): global_counter += 1 self.assertEqual(global_counter, 158) self.assertEqual(total_counter, 808) def test_xsd_11_components(self): total_counter = 0 global_counter = 0 for g in XMLSchema11.meta_schema.maps.iter_globals(): for c in g.iter_components(): total_counter += 1 if c.is_global(): global_counter += 1 self.assertEqual(global_counter, 183) self.assertEqual(total_counter, 972) def test_xsd_11_restrictions(self): all_model_type = XMLSchema11.meta_schema.types['all'] self.assertTrue( all_model_type.content.is_restriction(all_model_type.base_type.content) ) if __name__ == '__main__': import platform header_template = "Test xmlschema's global maps with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_groups.py����������������������������������������������������0000664�0000000�0000000�00000032166�14211403446�0022023�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from typing import Any, Union, List, Optional from xmlschema import XMLSchemaModelError, XMLSchemaModelDepthError from xmlschema.exceptions import XMLSchemaValueError from xmlschema.validators.particles import ParticleMixin from xmlschema.validators.groups import XsdGroup class ModelGroup(XsdGroup): """A subclass for testing XSD models, that disables element parsing and schema bindings.""" def __init__(self, model: str, min_occurs: int = 1, max_occurs: Optional[int] = 1) -> None: ParticleMixin.__init__(self, min_occurs, max_occurs) if model not in {'sequence', 'choice', 'all'}: raise XMLSchemaValueError("invalid model {!r} for a group".format(model)) self._group: List[Union[ParticleMixin, 'ModelGroup']] = [] self.model: str = model def __repr__(self) -> str: return '%s(model=%r, occurs=%r)' % (self.__class__.__name__, self.model, self.occurs) append: Any class TestXsdGroups(unittest.TestCase): def test_model_group_init(self): group = ModelGroup('sequence') self.assertEqual(group.model, 'sequence') with self.assertRaises(ValueError): ModelGroup('mixed') def test_model_group_repr(self): group = ModelGroup('choice') self.assertEqual(repr(group), "ModelGroup(model='choice', occurs=(1, 1))") def test_model_group_container(self): # group: List[GroupItemType] group = ModelGroup('choice') group.append(('a',)) self.assertListEqual(group[:], [('a',)]) group[0] = ('a', 'b') self.assertListEqual(group[:], [('a', 'b')]) group.append(('c',)) self.assertListEqual(group[:], [('a', 'b'), ('c',)]) del group[0] self.assertListEqual(group[:], [('c',)]) def test_is_empty(self): group = ModelGroup('all') self.assertTrue(group.is_empty()) group.append(('A',)) self.assertFalse(group.is_empty()) def test_is_pointless(self): root_group = ModelGroup('choice') group = ModelGroup('sequence') root_group.append(group) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('A',)) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('B',)) self.assertFalse(group.is_pointless(parent=root_group)) root_group = ModelGroup('sequence') group = ModelGroup('choice') root_group.append(group) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('A',)) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('B',)) self.assertFalse(group.is_pointless(parent=root_group)) root_group = ModelGroup('choice') group = ModelGroup('choice') root_group.append(group) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('A',)) self.assertTrue(group.is_pointless(parent=root_group)) group.append(('B',)) self.assertTrue(group.is_pointless(parent=root_group)) def test_effective_min_occurs(self): group = ModelGroup('sequence') self.assertEqual(group.effective_min_occurs, 0) group.append(ParticleMixin()) self.assertEqual(group.effective_min_occurs, 1) group.append(ParticleMixin()) group[0].min_occurs = 0 self.assertEqual(group.effective_min_occurs, 1) group.model = 'choice' self.assertEqual(group.effective_min_occurs, 0) group[1].min_occurs = 0 group.model = 'sequence' self.assertEqual(group.effective_min_occurs, 0) group.model = 'choice' group[0].min_occurs = group[1].min_occurs = 1 self.assertEqual(group.effective_min_occurs, 1) def test_effective_max_occurs(self): group = ModelGroup('sequence') self.assertEqual(group.effective_max_occurs, 0) group.append(ParticleMixin()) self.assertEqual(group.effective_max_occurs, 1) group.append(ParticleMixin(max_occurs=2)) self.assertEqual(group.effective_max_occurs, 1) group[0].min_occurs = group[0].max_occurs = 0 self.assertEqual(group.effective_max_occurs, 2) group[1].min_occurs = group[1].max_occurs = 0 self.assertEqual(group.effective_max_occurs, 0) group.append(ParticleMixin()) self.assertEqual(group.effective_max_occurs, 1) group[2].min_occurs = 0 self.assertEqual(group.effective_max_occurs, 1) group[0].max_occurs = None self.assertIsNone(group.effective_max_occurs) group[2].min_occurs = 1 group = ModelGroup('choice') group.append(ParticleMixin()) self.assertEqual(group.effective_max_occurs, 1) group.append(ParticleMixin()) group[0].min_occurs = group[0].max_occurs = 0 self.assertEqual(group.effective_max_occurs, 1) group[0].max_occurs = None self.assertIsNone(group.effective_max_occurs) group = ModelGroup('sequence') group.append(ParticleMixin()) self.assertEqual(group.effective_max_occurs, 1) group[0].max_occurs = None self.assertIsNone(group.effective_max_occurs) group[0].max_occurs = 1 self.assertEqual(group.effective_max_occurs, 1) group.max_occurs = None self.assertIsNone(group.effective_max_occurs) def test_has_occurs_restriction(self): group = ModelGroup('sequence') other = ModelGroup('sequence') other.append(ParticleMixin()) self.assertTrue(group.has_occurs_restriction(other)) group.append(ParticleMixin()) self.assertTrue(group.has_occurs_restriction(other)) for model in ['sequence', 'all', 'choice']: group = ModelGroup(model) group.append(ParticleMixin()) self.assertTrue(group.has_occurs_restriction(other=ParticleMixin())) self.assertFalse(group.has_occurs_restriction(other=ParticleMixin(2, 2))) self.assertTrue(group.has_occurs_restriction(other=ParticleMixin(1, None))) group.max_occurs = None self.assertFalse(group.has_occurs_restriction(other=ParticleMixin())) self.assertTrue(group.has_occurs_restriction(other=ParticleMixin(1, None))) def test_iter_model(self): # Model group with pointless inner groups root_group = group = ModelGroup('sequence') for k in range(3): for _ in range(k + 1): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) group = group[-1] particles = [e for e in root_group.iter_model()] self.assertEqual(len(particles), 6) for e in particles: self.assertIsInstance(e, ParticleMixin) self.assertNotIsInstance(e, ModelGroup) # Model group with no-pointless inner groups root_group = group = ModelGroup('sequence') for k in range(3): for _ in range(k + 1): group.append(ParticleMixin()) group.append(ModelGroup('sequence', max_occurs=None)) group = group[-1] particles = [e for e in root_group.iter_model()] self.assertEqual(len(particles), 2) self.assertIsInstance(particles[0], ParticleMixin) self.assertNotIsInstance(particles[0], ModelGroup) self.assertIsInstance(particles[1], ModelGroup) # Model group with an excessive depth root_group = group = ModelGroup('sequence') for k in range(16): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) group = group[1] with self.assertRaises(XMLSchemaModelDepthError): for _ in root_group.iter_model(): pass def test_iter_elements(self): # Model group with pointless inner groups root_group = group = ModelGroup('sequence') for k in range(3): for _ in range(k + 1): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) group = group[-1] particles = [e for e in root_group.iter_elements()] self.assertEqual(len(particles), 6) for e in particles: self.assertIsInstance(e, ParticleMixin) self.assertNotIsInstance(e, ModelGroup) # Model group with no-pointless inner groups root_group = group = ModelGroup('sequence') for k in range(3): for _ in range(k + 1): group.append(ParticleMixin()) group.append(ModelGroup('sequence', max_occurs=None)) group = group[-1] particles = [e for e in root_group.iter_elements()] self.assertEqual(len(particles), 6) for e in particles: self.assertIsInstance(e, ParticleMixin) self.assertNotIsInstance(e, ModelGroup) root_group.min_occurs = root_group.max_occurs = 0 self.assertListEqual(list(root_group.iter_elements()), []) # Model group with an excessive depth root_group = group = ModelGroup('sequence') for k in range(16): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) group = group[1] with self.assertRaises(XMLSchemaModelDepthError): for _ in root_group.iter_elements(): pass def test_get_subgroups(self): # Model group with pointless inner groups root_group = group = ModelGroup('sequence') subgroups = [] for k in range(4): for _ in range(k + 1): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) subgroups.append(group) group = group[-1] self.assertListEqual(root_group.get_subgroups(group), subgroups) self.assertListEqual(root_group.get_subgroups(subgroups[-1][0]), subgroups) self.assertListEqual(root_group.get_subgroups(subgroups[-2][0]), subgroups[:-1]) self.assertListEqual(root_group.get_subgroups(subgroups[-3][0]), subgroups[:-2]) self.assertListEqual(root_group.get_subgroups(subgroups[-4][0]), subgroups[:-3]) with self.assertRaises(XMLSchemaModelError): root_group.get_subgroups(ParticleMixin()) # Model group with an excessive depth root_group = group = ModelGroup('sequence') for k in range(18): group.append(ParticleMixin()) group.append(ModelGroup('sequence')) group = group[1] with self.assertRaises(XMLSchemaModelDepthError): root_group.get_subgroups(group) def test_overall_min_occurs(self): root_group = group = ModelGroup('sequence') subgroups = [] for k in range(4): group.append(ParticleMixin()) group.append(ModelGroup('sequence', max_occurs=10)) subgroups.append(group) group = group[-1] self.assertEqual(root_group.overall_min_occurs(group), 1) root_group[1].min_occurs = 0 self.assertEqual(root_group.overall_min_occurs(group), 0) root_group[1][1].min_occurs = 2 self.assertEqual(root_group.overall_min_occurs(group), 0) root_group[1].min_occurs = 1 self.assertEqual(root_group.overall_min_occurs(group), 2) root_group[1].min_occurs = 3 self.assertEqual(root_group.overall_min_occurs(group), 6) root_group = group = ModelGroup('choice') subgroups = [] for k in range(4): group.append(ParticleMixin()) group.append(ModelGroup('choice', max_occurs=10)) subgroups.append(group) group = group[-1] self.assertEqual(root_group.overall_min_occurs(group), 0) def test_overall_max_occurs(self): root_group = group = ModelGroup('sequence', min_occurs=0) subgroups = [] for k in range(4): group.append(ParticleMixin()) group.append(ModelGroup('sequence', min_occurs=0)) subgroups.append(group) group = group[-1] self.assertEqual(root_group.overall_max_occurs(group), 1) root_group[1].max_occurs = 0 self.assertEqual(root_group.overall_max_occurs(group), 0) root_group[1][1].max_occurs = 2 self.assertEqual(root_group.overall_max_occurs(group), 0) root_group[1].max_occurs = 1 self.assertEqual(root_group.overall_max_occurs(group), 2) root_group[1].max_occurs = 3 self.assertEqual(root_group.overall_max_occurs(group), 6) root_group[1].max_occurs = None self.assertIsNone(root_group.overall_max_occurs(group)) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD groups with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_identities.py������������������������������������������������0000664�0000000�0000000�00000045427�14211403446�0022651�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchemaParseError, XMLSchemaValidationError from xmlschema.validators import XMLSchema11 from xmlschema.validators.identities import IdentityCounter, KeyrefCounter from xmlschema.testing import XsdValidatorTestCase class TestXsdIdentities(XsdValidatorTestCase): def test_key_definition(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element>""") selector = schema.identities['key1'].selector self.assertTrue(selector.built) self.assertEqual(repr(selector), "XsdSelector(path='.')") def test_duplicated_key_name(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="secondary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 2) self.assertIn("duplicated value ('key1',)", schema.all_errors[0].message) def test_missing_key_name(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key> <xs:selector xpath="." /> <xs:field xpath="."/> </xs:key> </xs:element>""", validation='lax') errors = schema.all_errors if schema.XSD_VERSION == '1.0': self.assertEqual(len(errors), 3) self.assertEqual(errors[0].message, "missing required attribute 'name'") else: self.assertEqual(len(errors), 3) self.assertIn("missing key field '@name'", errors[0].message) def test_missing_selector(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:field xpath="."/> </xs:key> </xs:element>""", validation='lax') errors = schema.all_errors self.assertEqual(len(errors), 2) self.assertIn("Unexpected child with tag 'xs:field' at position 1", errors[0].message) schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:annotation/> </xs:key> </xs:element>""", validation='lax') errors = schema.all_errors self.assertEqual(len(errors), 2 if schema.XSD_VERSION == '1.0' else 1) self.assertEqual(errors[-1].message, "missing 'selector' declaration") def test_missing_selector_path(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector /> <!-- missing 'xpath' attribute --> <xs:field xpath="."/> </xs:key> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) self.assertEqual(schema.identities['key1'].selector.path, '*') def test_invalid_selector_path(self): with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="/" /> <!-- Invalid XPath selector expression --> <xs:field xpath="."/> </xs:key> </xs:element>""") self.assertEqual(ctx.exception.message, "invalid XPath expression for an XsdSelector") with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="xs : *" /> <!-- Invalid XPath expression --> <xs:field xpath="."/> </xs:key> </xs:element>""") self.assertIn("a QName cannot contains spaces", ctx.exception.message) def test_selector_target_namespace(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="xs:*"/> <xs:field xpath="."/> <xs:field xpath="@xs:*"/> </xs:key> </xs:element>""") self.assertEqual(schema.identities['key1'].selector.target_namespace, 'http://www.w3.org/2001/XMLSchema') self.assertEqual(schema.identities['key1'].fields[0].target_namespace, '') self.assertEqual(schema.identities['key1'].fields[1].target_namespace, 'http://www.w3.org/2001/XMLSchema') def test_invalid_selector_node(self): with self.assertRaises(XMLSchemaParseError) as ctx: self.check_schema(""" <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element ref="a" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="foo" type="xs:string"/> </xs:complexType> <xs:key name="node_key"> <xs:selector xpath="attribute::*"/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="a" type="xs:string"/>""") self.assertEqual(ctx.exception.message, 'selector xpath expression can only select elements') def test_key_validation(self): schema = self.check_schema(""" <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element ref="a" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:key name="node_key"> <xs:selector xpath="./a"/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="a" type="xs:string"/>""") self.assertTrue(schema.is_valid('<root><a>alpha</a><a>beta</a></root>')) self.assertFalse(schema.is_valid('<root><a>alpha</a><a>alpha</a></root>')) def test_missing_key_field(self): schema = self.check_schema(""" <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element ref="a" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:key name="node_key"> <xs:selector xpath="./a"/> <xs:field xpath="b"/> </xs:key> </xs:element> <xs:element name="a" type="xs:string"/>""") with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate('<root><a>alpha</a><a>beta</a></root>') self.assertIn("missing key field 'b'", ctx.exception.reason) def test_keyref(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""") self.assertTrue(schema.identities['keyref1'].built) refer = schema.identities['keyref1'].refer schema.identities['keyref1'].build() self.assertTrue(schema.identities['keyref1'].built) self.assertIs(schema.identities['keyref1'].refer, refer) def test_missing_keyref_refer(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="unknown_key"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) self.assertEqual(schema.all_errors[0].message, "key/unique identity constraint 'unknown_key' is missing") schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="x:key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) self.assertEqual(schema.all_errors[0].message, "prefix 'x' not found in namespace map") schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 2 if schema.XSD_VERSION == '1.0' else 1) self.assertEqual(schema.all_errors[-1].message, "missing required attribute 'refer'") def test_wrong_kind_keyref_refer(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="keyref2"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> <xs:keyref name="keyref2" refer="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) self.assertIn("reference to a non key/unique identity constraint", schema.all_errors[0].message) def test_cardinality_mismatch_keyref_refer(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""", validation='lax') self.assertEqual(len(schema.all_errors), 1) self.assertIn("field cardinality mismatch", schema.all_errors[0].message) def test_build(self): schema = self.check_schema(""" <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element ref="a" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="b" type="xs:string"/> </xs:complexType> <xs:key name="key1"> <xs:selector xpath=".//root/a"/> <xs:field xpath="@b"/> </xs:key> </xs:element> <xs:element name="a"> <xs:complexType> <xs:attribute name="b" type="xs:string"/> </xs:complexType> </xs:element>""") self.assertEqual(schema.identities['key1'].elements, {schema.elements['a']: None}) def test_identity_counter(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element>""") counter = IdentityCounter(schema.identities['key1']) self.assertEqual(repr(counter), 'IdentityCounter()') self.assertIsNone(counter.increase(('1',))) self.assertIsNone(counter.increase(('2',))) self.assertEqual(repr(counter), "IdentityCounter({('1',): 1, ('2',): 1})") with self.assertRaises(ValueError) as ctx: counter.increase(('1',)) self.assertIn("duplicated value ('1',)", str(ctx.exception)) self.assertIsNone(counter.increase(('1',))) self.assertEqual(counter.counter[('1',)], 3) def test_keyref_counter(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element>""") counter = KeyrefCounter(schema.identities['keyref1']) self.assertIsNone(counter.increase(('1',))) self.assertIsNone(counter.increase(('2',))) self.assertIsNone(counter.increase(('1',))) self.assertIsNone(counter.increase(('3',))) self.assertIsNone(counter.increase(('3',))) self.assertIsNone(counter.increase(('4',))) with self.assertRaises(KeyError): list(counter.iter_errors(identities={})) key_counter = IdentityCounter(schema.identities['key1']) self.assertIsNone(key_counter.increase(('1',))) self.assertIsNone(key_counter.increase('4')) identities = {schema.identities['key1']: key_counter} errors = list(counter.iter_errors(identities)) self.assertEqual(len(errors), 2) self.assertIn("value ('2',) not found", str(errors[0])) self.assertIn("value ('3',) not found", str(errors[1])) self.assertIn("(2 times)", str(errors[1])) class TestXsd11Identities(TestXsdIdentities): schema_class = XMLSchema11 def test_key_reference_definition(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="secondary_key" type="xs:string"> <xs:key ref="key1"/> </xs:element>""") key1 = schema.identities['key1'] self.assertIsNot(schema.elements['secondary_key'].identities['key1'], key1) self.assertIs(schema.elements['secondary_key'].identities['key1'].ref, key1) def test_missing_key_reference_definition(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="secondary_key" type="xs:string"> <xs:key ref="unknown_key"/> </xs:element>""", validation='lax') errors = schema.all_errors self.assertEqual(len(errors), 1) self.assertEqual("unknown identity constraint 'unknown_key'", errors[0].message) def test_different_kind_key_reference_definition(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> </xs:element> <xs:element name="secondary_key" type="xs:string"> <xs:unique ref="key1"/> </xs:element>""", validation='lax') errors = schema.all_errors self.assertEqual(len(errors), 1) self.assertEqual("attribute 'ref' points to a different kind constraint", errors[0].message) def test_keyref_reference_definition(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:key> <xs:keyref name="keyref1" refer="key1"> <xs:selector xpath="."/> <xs:field xpath="."/> </xs:keyref> </xs:element> <xs:element name="secondary_key" type="xs:string"> <xs:keyref ref="keyref1"/> </xs:element>""") self.assertIsNot(schema.elements['secondary_key'].identities['keyref1'], schema.elements['primary_key'].identities['keyref1']) self.assertIs(schema.elements['secondary_key'].identities['keyref1'].ref, schema.elements['primary_key'].identities['keyref1']) def test_selector_default_namespace(self): schema = self.check_schema(""" <xs:element name="primary_key" type="xs:string"> <xs:key name="key1"> <xs:selector xpath="." xpathDefaultNamespace="https://xmlschema.test/ns"/> <xs:field xpath="." xpathDefaultNamespace="##targetNamespace"/> </xs:key> </xs:element>""") self.assertEqual(schema.identities['key1'].selector.xpath_default_namespace, 'https://xmlschema.test/ns') self.assertEqual(schema.identities['key1'].fields[0].xpath_default_namespace, '') if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD identities with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_models.py����������������������������������������������������0000664�0000000�0000000�00000147752�14211403446�0021777�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Tests concerning model groups validation""" import unittest import os.path from textwrap import dedent from typing import Any, Union, List, Optional from xmlschema import XMLSchema10, XMLSchema11 from xmlschema.exceptions import XMLSchemaValueError from xmlschema.validators.exceptions import XMLSchemaValidationError from xmlschema.validators.particles import ParticleMixin from xmlschema.validators.models import distinguishable_paths, ModelVisitor from xmlschema.validators.groups import XsdGroup from xmlschema.validators.elements import XsdElement from xmlschema.testing import XsdValidatorTestCase class ModelGroup(XsdGroup): """A subclass for testing XSD models, that disables element parsing and schema bindings.""" def __init__(self, model: str, min_occurs: int = 1, max_occurs: Optional[int] = 1) -> None: ParticleMixin.__init__(self, min_occurs, max_occurs) if model not in {'sequence', 'choice', 'all'}: raise XMLSchemaValueError("invalid model {!r} for a group".format(model)) self._group: List[Union[ParticleMixin, 'ModelGroup']] = [] self.model: str = model def __repr__(self) -> str: return '%s(model=%r, occurs=%r)' % (self.__class__.__name__, self.model, self.occurs) append: Any class TestModelValidation(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') schema_class = XMLSchema10 # --- Test helper functions --- def check_advance_true(self, model, expected=None): """ Advances a model with a match condition and checks the expected error list or exception. :param model: an ModelGroupVisitor instance. :param expected: can be an exception class or a list. Leaving `None` means that an empty \ list is expected. """ if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, lambda x: list(model.advance(x)), True) else: self.assertEqual([e for e in model.advance(True)], expected or []) def check_advance_false(self, model, expected=None): """ Advances a model with a no-match condition and checks the expected error list or or exception. :param model: an ModelGroupVisitor instance. :param expected: can be an exception class or a list. Leaving `None` means that \ an empty list is expected. """ if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, lambda x: list(model.advance(x)), False) else: self.assertEqual([e for e in model.advance(False)], expected or []) def check_advance(self, model, match, expected=None): """ Advances a model with an argument match condition and checks the expected error list. :param model: an ModelGroupVisitor instance. :param match: the matching boolean condition. :param expected: can be an exception class or a list. Leaving `None` means that an empty \ list is expected. """ if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, lambda x: list(model.advance(x)), match) else: self.assertEqual([e for e in model.advance(match)], expected or []) def check_stop(self, model, expected=None): """ Stops a model and checks the expected errors list. :param model: an ModelGroupVisitor instance. :param expected: can be an exception class or a list. Leaving `None` means that an empty \ list is expected. """ if isinstance(expected, type) and issubclass(expected, Exception): self.assertRaises(expected, lambda: list(model.stop())) else: self.assertEqual([e for e in model.stop()], expected or []) # --- ModelVisitor methods --- def test_iter_group(self): group = ModelGroup('sequence', min_occurs=0, max_occurs=0) model = ModelVisitor(group) self.assertListEqual(list(model.items), []) group = ModelGroup('choice') group.append(ParticleMixin()) group.append(ParticleMixin()) group.append(ParticleMixin()) model = ModelVisitor(group) model.occurs[group[1]] = 1 self.assertListEqual(list(model.items), group[1:]) group = ModelGroup('all') group.append(ParticleMixin()) group.append(ParticleMixin()) group.append(ParticleMixin()) model = ModelVisitor(group) model.occurs[group[1]] = 1 self.assertListEqual(list(model.items), group[2:]) # --- Vehicles schema --- def test_vehicles_model(self): # Sequence with two not-emptiable single-occurs elements group = self.vh_schema.elements['vehicles'].type.content model = ModelVisitor(group) self.check_advance_true(model) # <cars> self.check_advance_true(model) # <bikes> self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_true(model) # <cars> self.check_advance_true(model) # <bikes> self.check_advance_true(model, ValueError) # <bikes> self.assertIsNone(model.element) def test_cars_model(self): # Emptiable 1:1 sequence with one emptiable and unlimited element. group = self.vh_schema.elements['cars'].type.content model = ModelVisitor(group) self.check_advance_true(model) # <car> self.check_advance_true(model) # <car> self.check_advance_true(model) # <car> self.check_advance_false(model) # (end) self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model) # <not-a-car> self.assertIsNone(model.element) # --- Collection schema --- def test_collection_model(self): # Sequence with one not-emptiable and unlimited element. group = self.col_schema.elements['collection'].type.content model = ModelVisitor(group) self.check_advance_true(model) # <car> self.check_advance_true(model) # <car> self.check_advance_true(model) # <car> self.check_advance_true(model) # <car> self.check_advance_false(model) # (end) self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model, [(group[0], 0, [group[0]])]) # <not-a-car> self.assertIsNone(model.element) def test_person_type_model(self): # Sequence with four single elements, last two are also emptiable. group = self.col_schema.types['personType'].content model = ModelVisitor(group) self.check_advance_true(model) # <name> self.check_advance_true(model) # <born> self.check_advance_true(model) # <dead> self.check_advance_true(model) # <qualification> self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_true(model) # <name> self.check_advance_true(model) # <born> self.check_stop(model) self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_true(model) # <name> match self.check_advance_false(model, [(group[1], 0, [group[1]])]) # <born> missing! self.check_advance_true(model) # <dead> match self.check_stop(model) # <qualification> is optional self.assertIsNone(model.element) # --- XSD 1.0/1.1 meta-schema models --- def test_meta_simple_derivation_model(self): """ <xs:group name="simpleDerivation"> <xs:choice> <xs:element ref="xs:restriction"/> <xs:element ref="xs:list"/> <xs:element ref="xs:union"/> </xs:choice> </xs:group> """ group = XMLSchema10.meta_schema.groups['simpleDerivation'] model = ModelVisitor(group) self.check_advance_true(model) # <restriction> matches self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model) # <list> doesn't match with <restriction> self.check_advance_true(model) # <list> matches self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model) # <union> doesn't match with <restriction> self.check_advance_false(model) # <union> doesn't match with <list> self.check_advance_true(model) # <union> matches self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model) # <other> doesn't match with <restriction> self.check_advance_false(model) # <other> doesn't match with <list> self.check_advance_false(model, [(group, 0, group[:])]) # <other> doesn't match with <union> self.assertIsNone(model.element) def test_meta_simple_restriction_model(self): """ <!-- XSD 1.0 --> <xs:group name="facets"> <xs:choice> <xs:element ref="xs:minExclusive"/> <xs:element ref="xs:minInclusive"/> <xs:element ref="xs:maxExclusive"/> <xs:element ref="xs:maxInclusive"/> <xs:element ref="xs:totalDigits"/> <xs:element ref="xs:fractionDigits"/> <xs:element ref="xs:length"/> <xs:element ref="xs:minLength"/> <xs:element ref="xs:maxLength"/> <xs:element ref="xs:enumeration"/> <xs:element ref="xs:whiteSpace"/> <xs:element ref="xs:pattern"/> </xs:choice> </xs:group> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:group ref="xs:facets" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <!-- XSD 1.1 --> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:facet"/> <!-- Use a substitution group --> <xs:any processContents="lax" namespace="##other"/> </xs:choice> </xs:sequence> </xs:group> """ # Sequence with an optional single element and an optional unlimited choice. group = self.schema_class.meta_schema.groups['simpleRestrictionModel'] model = ModelVisitor(group) if self.schema_class.XSD_VERSION == '1.0': self.assertEqual(model.element, group[0]) self.check_advance_true(model) # <simpleType> matches self.assertEqual(model.element, group[1][0][0]) self.check_advance_false(model) # <maxExclusive> does not match self.assertEqual(model.element, group[1][0][1]) self.check_advance_false(model) # <maxExclusive> does not match self.assertEqual(model.element, group[1][0][2]) self.check_advance_true(model) # <maxExclusive> matches self.assertEqual(model.element, group[1][0][0]) for _ in range(12): self.check_advance_false(model) # no match for the inner choice group "xs:facets" self.assertIsNone(model.element) def test_meta_schema_top_model(self): """ <xs:group name="schemaTop"> <xs:choice> <xs:group ref="xs:redefinable"/> <xs:element ref="xs:element"/> <xs:element ref="xs:attribute"/> <xs:element ref="xs:notation"/> </xs:choice> </xs:group> <xs:group name="redefinable"> <xs:choice> <xs:element ref="xs:simpleType"/> <xs:element ref="xs:complexType"/> <xs:element ref="xs:group"/> <xs:element ref="xs:attributeGroup"/> </xs:choice> </xs:group> """ group = self.schema_class.meta_schema.groups['schemaTop'] model = ModelVisitor(group) self.assertEqual(model.element, group[0][0][0]) self.check_advance_false(model) # <simpleType> doesn't match self.assertEqual(model.element, group[0][0][1]) self.check_advance_true(model) # <complexType> matches self.assertIsNone(model.element) model.restart() self.assertEqual(model.element, group[0][0][0]) self.check_advance_false(model) # <simpleType> doesn't match self.assertEqual(model.element, group[0][0][1]) self.check_advance_false(model) # <complexType> doesn't match self.assertEqual(model.element, group[0][0][2]) self.check_advance_false(model) # <group> doesn't match self.assertEqual(model.element, group[0][0][3]) self.check_advance_false(model) # <attributeGroup> doesn't match self.assertEqual(model.element, group[1]) self.check_advance_false(model) # <element> doesn't match self.assertEqual(model.element, group[2]) self.check_advance_false(model) # <attribute> doesn't match self.assertEqual(model.element, group[3]) self.check_advance_false( model, [(group, 0, group[0][0][:] + group[1:])]) # <notation> doesn't match model.restart() self.assertEqual(model.element, group[0][0][0]) self.check_advance_false(model) # <simpleType> doesn't match self.assertEqual(model.element, group[0][0][1]) self.check_advance_false(model) # <complexType> doesn't match self.assertEqual(model.element, group[0][0][2]) self.check_advance_false(model) # <group> doesn't match self.assertEqual(model.element, group[0][0][3]) self.check_advance_false(model) # <attributeGroup> doesn't match self.assertEqual(model.element, group[1]) self.check_advance_false(model) # <element> doesn't match self.assertEqual(model.element, group[2]) self.check_advance_true(model) # <attribute> doesn't match self.assertIsNone(model.element) def test_meta_attr_declarations_group(self): """ <xs:group name="attrDecls"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="attribute" type="xs:attribute"/> <xs:element name="attributeGroup" type="xs:attributeGroupRef"/> </xs:choice> <xs:element ref="xs:anyAttribute" minOccurs="0"/> </xs:sequence> </xs:group> """ group = self.schema_class.meta_schema.groups['attrDecls'] model = ModelVisitor(group) for match in [False, False, True]: self.check_advance(model, match) self.assertIsNone(model.element) model = ModelVisitor(group) self.check_advance_false(model) self.check_advance_true(model) self.assertEqual(model.element, group[0][0]) model = ModelVisitor(group) for match in [False, True, False, False]: self.check_advance(model, match) self.assertEqual(model.element, group[1]) model = ModelVisitor(group) for match in [False, True, True, False, True, False, False]: self.check_advance(model, match) self.assertEqual(model.element, group[1]) def test_meta_complex_type_model(self): """ <xs:group name="complexTypeModel"> <xs:choice> <xs:element ref="xs:simpleContent"/> <xs:element ref="xs:complexContent"/> <xs:sequence> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> </xs:choice> </xs:group> <xs:group name="typeDefParticle"> <xs:choice> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> </xs:choice> </xs:group> <xs:group name="complexTypeModel"> <xs:choice> <xs:element ref="xs:simpleContent"/> <xs:element ref="xs:complexContent"/> <xs:sequence> <xs:element ref="xs:openContent" minOccurs="0"/> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> </xs:choice> </xs:group> """ group = self.schema_class.meta_schema.groups['complexTypeModel'] model = ModelVisitor(group) self.assertEqual(model.element, group[0]) self.check_advance_true(model) # <simpleContent> matches self.assertIsNone(model.element) model.restart() self.assertEqual(model.element, group[0]) self.check_advance_false(model) self.check_advance_true(model) # <complexContent> matches self.assertIsNone(model.element) if self.schema_class.XSD_VERSION == '1.0': model.restart() self.assertEqual(model.element, group[0]) for match in [False, False, False, False, True]: self.check_advance(model, match) # <all> matches self.check_stop(model) self.assertIsNone(model.element) model.restart() self.assertEqual(model.element, group[0]) for match in [False, False, False, False, True, False, True, False, False, False]: self.check_advance(model, match) # <all> and <attributeGroup> match self.assertIsNone(model.element) def test_meta_schema_document_model(self): group = self.schema_class.meta_schema.elements['schema'].type.content # A schema model with a wrong tag model = ModelVisitor(group) if self.schema_class.XSD_VERSION == '1.0': self.assertEqual(model.element, group[0][0]) self.check_advance_false(model) # eg. anyAttribute self.check_stop(model) else: self.assertEqual(model.element, group[0][0][0]) # # Tests on schema test_cases/features/models/models.xsd def test_model_group1(self): group = self.models_schema.groups['group1'] model = ModelVisitor(group) self.assertEqual(model.element, group[0]) self.check_stop(model) model.restart() self.assertEqual(model.element, group[0]) for _ in range(3): self.check_advance_false(model) self.assertIsNone(model.element) model.restart() for match in [False, True, False]: self.check_advance(model, match) self.assertIsNone(model.element) def test_model_group2(self): group = self.models_schema.groups['group2'] model = ModelVisitor(group) self.assertEqual(model.element, group[0]) for _ in range(3): self.check_advance_false(model) # group1 do not match self.assertEqual(model.element, group[1][0][0][2]) # <elem3> of group1 for _ in range(8): self.check_advance_false(model) self.assertEqual(model.element, group[2]) # <elem12> self.check_advance_false(model) self.assertEqual(model.element, group[3]) # <elem13> self.check_advance_false(model) self.assertIsNone(model.element) def test_model_group3(self): group = self.models_schema.groups['group3'] model = ModelVisitor(group) self.assertEqual(model.element, group[0]) for match in [True, False, True]: self.check_advance(model, match) self.check_stop(model) def test_model_group4(self): group = self.models_schema.groups['group4'] model = ModelVisitor(group) self.assertEqual(model.element, group[0]) for match in [True, False, True]: self.check_advance(model, match) self.check_stop(model) def test_model_group5(self): group = self.models_schema.groups['group5'] model = ModelVisitor(group) self.assertEqual(model.element, group[0][0]) for _ in range(5): # match [<elem1> .. <elem5>] self.check_advance_true(model) self.assertEqual(model.element.name, 'elem6') self.check_advance_true(model) # match choice with <elem6> self.check_stop(model) def test_model_group6(self): group = self.models_schema.groups['group6'] model = ModelVisitor(group) self.assertEqual(model.element, group[0][0]) self.check_advance_true(model) # match choice with <elem1> self.check_advance_true(model) # match choice with <elem2> self.assertIsNone(model.element) def test_model_group7(self): group = self.models_schema.types['complexType7'].content model = ModelVisitor(group) self.assertEqual(model.element, group[0][0]) self.check_stop(model, [(group[0][0], 0, [group[0][0]])]) group = self.models_schema.types['complexType7_emptiable'].content model = ModelVisitor(group) self.assertEqual(model.element, group[0][0]) self.check_stop(model) def test_model_group8(self): group = self.models_schema.groups['group8'] model = ModelVisitor(group) self.assertEqual(model.element, group[0][0]) self.check_advance_true(model) # match choice with <elem1> self.check_advance_false(model) self.assertEqual(model.element, group[0][1]) self.check_advance_true(model) # match choice with <elem2> self.assertEqual(model.element, group[0][2]) self.check_advance_true(model) # match choice with <elem3> self.assertEqual(model.element, group[0][3]) self.check_advance_true(model) # match choice with <elem4> self.assertIsNone(model.element) # # Test pathological cases def test_empty_choice_groups(self): schema = self.schema_class("""<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:group name="group1"> <xs:sequence> <xs:choice minOccurs="0"> <xs:choice minOccurs="0"/> </xs:choice> <xs:element name="elem1"/> </xs:sequence> </xs:group> <xs:element name="root"> <xs:complexType> <xs:choice> <xs:group ref="group1"/> </xs:choice> </xs:complexType> </xs:element> </xs:schema>""") xml_data = "<root><elem1/></root>" model = ModelVisitor(schema.elements['root'].type.content) self.assertIsInstance(model.element, XsdElement) self.assertEqual(model.element.name, 'elem1') self.assertIsNone(schema.validate(xml_data)) # W3C test group 'complex022' schema = self.schema_class("""<?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:choice/> </xs:complexType> </xs:element> </xs:schema>""") reason = "an empty 'choice' group with minOccurs > 0 cannot validate any content" with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate("<root><elem1/></root>") self.assertIn(reason, str(ctx.exception)) with self.assertRaises(XMLSchemaValidationError) as ctx: schema.validate("<root/>") self.assertIn(reason, str(ctx.exception)) def test_single_item_groups(self): schema = self.schema_class("""<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="a1"> <xs:complexType> <xs:choice> <xs:any maxOccurs="2" processContents="lax"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="a2"> <xs:complexType> <xs:choice> <xs:any maxOccurs="2" processContents="strict"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="a3"> <xs:complexType> <xs:sequence> <xs:any maxOccurs="2" processContents="lax"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="a4"> <xs:complexType> <xs:choice> <xs:element name="b" maxOccurs="2"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="a5"> <xs:complexType> <xs:sequence> <xs:element name="b" maxOccurs="2"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="b"/> </xs:schema>""") self.assertFalse(schema.is_valid('<a1></a1>')) self.assertFalse(schema.is_valid('<a2></a2>')) self.assertFalse(schema.is_valid('<a3></a3>')) self.assertFalse(schema.is_valid('<a4></a4>')) self.assertFalse(schema.is_valid('<a5></a5>')) self.assertTrue(schema.is_valid('<a1><c/></a1>')) self.assertFalse(schema.is_valid('<a2><c/></a2>')) self.assertTrue(schema.is_valid('<a3><c/></a3>')) self.assertFalse(schema.is_valid('<a4><c/></a4>')) self.assertFalse(schema.is_valid('<a5><c/></a5>')) self.assertTrue(schema.is_valid('<a1><b/></a1>')) self.assertTrue(schema.is_valid('<a2><b/></a2>')) self.assertTrue(schema.is_valid('<a3><b/></a3>')) self.assertTrue(schema.is_valid('<a4><b/></a4>')) self.assertTrue(schema.is_valid('<a5><b/></a5>')) self.assertTrue(schema.is_valid('<a1><b/><b/></a1>')) self.assertTrue(schema.is_valid('<a2><b/><b/></a2>')) self.assertTrue(schema.is_valid('<a3><b/><b/></a3>')) self.assertTrue(schema.is_valid('<a4><b/><b/></a4>')) self.assertTrue(schema.is_valid('<a5><b/><b/></a5>')) self.assertFalse(schema.is_valid('<a1><b/><b/><b/></a1>')) self.assertFalse(schema.is_valid('<a2><b/><b/><b/></a2>')) self.assertFalse(schema.is_valid('<a3><b/><b/><b/></a3>')) self.assertFalse(schema.is_valid('<a4><b/><b/><b/></a4>')) self.assertFalse(schema.is_valid('<a5><b/><b/><b/></a5>')) def test_sequence_model_with_extended_occurs(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence minOccurs="2" maxOccurs="unbounded"> <xs:element name="ax" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> """) self.assertIsNone(schema.validate('<root><ax/><ax/></root>')) schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:element name="a" minOccurs="2" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> """) self.assertIsNone(schema.validate('<root><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/><a/><a/><a/></root>')) def test_sequence_model_with_nested_choice_model(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:group ref="group1" minOccurs="2" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:group name="group1"> <xs:choice> <xs:element name="a" maxOccurs="unbounded"/> <xs:element name="b"/> <xs:element name="c"/> </xs:choice> </xs:group> </xs:schema> """) self.assertIsNone(schema.validate('<root><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/><a/><a/><a/></root>')) def test_sequence_model_with_optional_elements(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence minOccurs="2" maxOccurs="2"> <xs:element name="a" minOccurs="1" maxOccurs="2" /> <xs:element name="b" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:schema> """) self.assertIsNone(schema.validate('<root><a/><a/><b/></root>')) def test_choice_model_with_extended_occurs(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:choice maxOccurs="unbounded" minOccurs="0"> <xs:element maxOccurs="5" minOccurs="3" name="a"/> <xs:element maxOccurs="5" minOccurs="3" name="b"/> </xs:choice> </xs:complexType> </xs:element> </xs:schema> """) self.assertIsNone(schema.validate('<root><a/><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/><a/><a/></root>')) self.assertIsNone(schema.validate('<root><a/><a/><a/><a/><a/><a/></root>')) schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:choice minOccurs="2" maxOccurs="3"> <xs:element name="a" maxOccurs="unbounded"/> <xs:element name="b" maxOccurs="unbounded"/> <xs:element name="c"/> </xs:choice> </xs:complexType> </xs:element> </xs:schema> """) self.assertIsNone(schema.validate('<root><a/><a/><a/></root>')) def test_emptiable_all_model(self): schema = self.schema_class(dedent( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:all minOccurs="0"> <xs:element name="a" /> <xs:element name="b" /> </xs:all> </xs:complexType> </xs:element> </xs:schema> """)) self.assertIsNone(schema.validate('<root><b/><a/></root>')) self.assertIsNone(schema.validate('<root/>')) self.assertFalse(schema.is_valid('<root><b/></root>')) # # Tests on issues def test_issue_086(self): issue_086_xsd = self.casepath('issues/issue_086/issue_086.xsd') schema = self.schema_class(issue_086_xsd) group = schema.types['Foo'].content # issue_086-1.xml sequence simulation model = ModelVisitor(group) self.assertEqual(model.element, group[0]) self.check_advance_true(model) # <header> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_true(model) # <a> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_true(model) # <a> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_false(model) self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_false(model) self.assertEqual(model.element, group[1][1][0]) # 'b' element self.check_advance_true(model) # <b> matching self.assertEqual(model.element, group[1][1][0]) # 'b' element self.check_advance_true(model) # <b> matching self.check_advance_false(model) self.assertEqual(model.element, group[1][0][0]) # 'a' element (choice group restarted) self.check_advance_false(model) self.check_advance_false(model) self.assertEqual(model.element, group[1][2][0]) # 'c' element self.check_advance_true(model) # <c> matching self.assertEqual(model.element, group[1][2][0]) # 'c' element self.check_advance_true(model) # <c> matching self.check_stop(model) # issue_086-2.xml sequence simulation model = ModelVisitor(group) self.check_advance_true(model) # <header> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_false(model) self.assertEqual(model.element, group[1][1][0]) # 'b' element self.check_advance_true(model) # <b> matching self.assertEqual(model.element, group[1][1][0]) # 'b' element self.check_advance_true(model) # <b> matching self.check_advance_false(model) self.assertEqual(model.element, group[1][0][0]) # 'a' element (choice group restarted) self.check_advance_false(model) self.check_advance_false(model) self.assertEqual(model.element, group[1][2][0]) # 'c' element self.check_advance_true(model) # <c> matching self.assertEqual(model.element, group[1][2][0]) # 'c' element self.check_advance_true(model) # <c> matching self.check_advance_false(model) self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_true(model) # <a> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_advance_true(model) # <a> matching self.assertEqual(model.element, group[1][0][0]) # 'a' element self.check_stop(model) class TestModelValidation11(TestModelValidation): schema_class = XMLSchema11 def test_all_model_with_wildcard(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:all> <xs:element name="a" type="xs:string" /> <xs:any maxOccurs="3" processContents="lax" /> </xs:all> </xs:complexType> </xs:element> </xs:schema> """) xml_data = """ <root> <wildcard1/> <a>1</a> <wildcard2/> <wildcard3/> </root> """ self.assertIsNone(schema.validate(xml_data)) def test_all_model_with_extended_occurs(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:all> <xs:element name="a" minOccurs="0" maxOccurs="5"/> <xs:element name="b" maxOccurs="5"/> <xs:element name="c" minOccurs="2" maxOccurs="5"/> <xs:element name="d" /> </xs:all> </xs:complexType> </xs:element> </xs:schema> """) xml_data = '<root><a/><b/><d/><c/><a/><c/></root>' self.assertIsNone(schema.validate(xml_data)) def test_all_model_with_relaxed_occurs(self): schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:all> <xs:element name="a" minOccurs="0" maxOccurs="5"/> <xs:element name="b" maxOccurs="5"/> <xs:element name="c" minOccurs="2" maxOccurs="unbounded"/> <xs:element name="d" /> </xs:all> </xs:complexType> </xs:element> </xs:schema> """) xml_data = '<root><a/><b/><d/><c/><a/><c/><c/><a/><a/><b/></root>' self.assertIsNone(schema.validate(xml_data)) schema = self.schema_class( """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:all> <xs:element name="a" minOccurs="0" maxOccurs="5"/> <xs:group ref="group1"/> </xs:all> </xs:complexType> </xs:element> <xs:group name="group1"> <xs:all> <xs:element name="b" maxOccurs="5"/> <xs:element name="c" minOccurs="2" maxOccurs="unbounded"/> <xs:element name="d" /> </xs:all> </xs:group> </xs:schema> """) self.assertIsNone(schema.validate(xml_data)) class TestModelBasedSorting(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), 'test_cases') def test_sort_content(self): # test of ModelVisitor's sort_content/iter_unordered_content schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence> <xs:element name="B1" type="xs:string"/> <xs:element name="B2" type="xs:integer"/> <xs:element name="B3" type="xs:boolean"/> </xs:sequence> </xs:complexType> """) model = ModelVisitor(schema.types['A_type'].content) self.assertListEqual( model.sort_content([('B2', 10), ('B1', 'abc'), ('B3', True)], restart=False), [('B1', 'abc'), ('B2', 10), ('B3', True)] ) self.assertListEqual( model.sort_content([('B2', 10), ('B1', 'abc'), ('B3', True)]), [('B1', 'abc'), ('B2', 10), ('B3', True)] ) self.assertListEqual( model.sort_content([('B2', 10), ('B1', 'abc'), ('B3', True)], restart=False), [('B2', 10), ('B1', 'abc'), ('B3', True)] ) self.assertListEqual( model.sort_content([('B3', True), ('B2', 10), ('B1', 'abc')]), [('B1', 'abc'), ('B2', 10), ('B3', True)] ) self.assertListEqual( model.sort_content([('B2', 10), ('B4', None), ('B1', 'abc'), ('B3', True)]), [('B1', 'abc'), ('B2', 10), ('B3', True), ('B4', None)] ) content = [('B2', 10), ('B4', None), ('B1', 'abc'), (1, 'hello'), ('B3', True)] self.assertListEqual( model.sort_content(content), [(1, 'hello'), ('B1', 'abc'), ('B2', 10), ('B3', True), ('B4', None)] ) content = [ (2, 'world!'), ('B2', 10), ('B4', None), ('B1', 'abc'), (1, 'hello'), ('B3', True) ] self.assertListEqual( model.sort_content(content), [(1, 'hello'), ('B1', 'abc'), (2, 'world!'), ('B2', 10), ('B3', True), ('B4', None)] ) content = [ ('B2', 10), ('B4', None), ('B1', 'abc'), ('B3', True), (6, 'six'), (5, 'five'), (4, 'four'), (2, 'two'), (3, 'three'), (1, 'one') ] self.assertListEqual( model.sort_content(content), [(1, 'one'), ('B1', 'abc'), (2, 'two'), ('B2', 10), (3, 'three'), ('B3', True), (4, 'four'), ('B4', None), (5, 'five'), (6, 'six')] ) # With a dict-type argument content = dict([('B2', [10]), ('B1', ['abc']), ('B3', [True])]) self.assertListEqual( model.sort_content(content), [('B1', 'abc'), ('B2', 10), ('B3', True)] ) content = dict([('B2', [10]), ('B1', ['abc']), ('B3', [True]), (1, 'hello')]) self.assertListEqual( model.sort_content(content), [(1, 'hello'), ('B1', 'abc'), ('B2', 10), ('B3', True)] ) # With partial content self.assertListEqual(model.sort_content([]), []) self.assertListEqual(model.sort_content([('B1', 'abc')]), [('B1', 'abc')]) self.assertListEqual(model.sort_content([('B2', 10)]), [('B2', 10)]) self.assertListEqual(model.sort_content([('B3', True)]), [('B3', True)]) self.assertListEqual( model.sort_content([('B3', True), ('B1', 'abc')]), [('B1', 'abc'), ('B3', True)] ) self.assertListEqual( model.sort_content([('B2', 10), ('B1', 'abc')]), [('B1', 'abc'), ('B2', 10)] ) self.assertListEqual( model.sort_content([('B3', True), ('B2', 10)]), [('B2', 10), ('B3', True)] ) def test_iter_collapsed_content_with_optional_elements(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence> <xs:element name="B1" minOccurs="0" /> <xs:element name="B2" minOccurs="0" /> <xs:element name="B3" /> <xs:element name="B4" /> <xs:element name="B5" /> <xs:element name="B6" minOccurs="0" /> <xs:element name="B7" /> </xs:sequence> </xs:complexType> """) model = ModelVisitor(schema.types['A_type'].content) content = [('B3', 10), ('B4', None), ('B5', True), ('B6', 'alpha'), ('B7', 20)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), content ) content = [('B3', 10), ('B5', True), ('B6', 'alpha'), ('B7', 20)] # Missing B4 model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), content ) def test_iter_collapsed_content_with_repeated_elements(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence> <xs:element name="B1" minOccurs="0" /> <xs:element name="B2" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="B3" maxOccurs="unbounded" /> <xs:element name="B4" /> <xs:element name="B5" maxOccurs="unbounded" /> <xs:element name="B6" minOccurs="0" /> <xs:element name="B7" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> """) model = ModelVisitor(schema.types['A_type'].content) content = [ ('B3', 10), ('B4', None), ('B5', True), ('B5', False), ('B6', 'alpha'), ('B7', 20) ] self.assertListEqual( list(model.iter_collapsed_content(content)), content ) content = [('B3', 10), ('B3', 11), ('B3', 12), ('B4', None), ('B5', True), ('B5', False), ('B6', 'alpha'), ('B7', 20), ('B7', 30)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), content ) content = [('B3', 10), ('B3', 11), ('B3', 12), ('B4', None), ('B5', True), ('B5', False)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), content ) def test_iter_collapsed_content_with_repeated_groups(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence minOccurs="1" maxOccurs="2"> <xs:element name="B1" minOccurs="0" /> <xs:element name="B2" minOccurs="0" /> </xs:sequence> </xs:complexType> """) model = ModelVisitor(schema.types['A_type'].content) content = [('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4)] self.assertListEqual( list(model.iter_collapsed_content(content)), [('B1', 1), ('B2', 3), ('B1', 2), ('B2', 4)] ) # Model broken by unknown element at start content = [('X', None), ('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B1', 1), ('X', None), ('B1', 2), ('B2', 3), ('B2', 4)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B1', 1), ('B1', 2), ('X', None), ('B2', 3), ('B2', 4)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B1', 1), ('B1', 2), ('B2', 3), ('X', None), ('B2', 4)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), [('B1', 1), ('B2', 3), ('B1', 2), ('X', None), ('B2', 4)] ) content = [('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4), ('X', None)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), [('B1', 1), ('B2', 3), ('B1', 2), ('B2', 4), ('X', None)] ) def test_iter_collapsed_content_with_single_elements(self): schema = self.get_schema(""" <xs:element name="A" type="A_type" /> <xs:complexType name="A_type"> <xs:sequence> <xs:element name="B1" /> <xs:element name="B2" /> <xs:element name="B3" /> </xs:sequence> </xs:complexType> """) model = ModelVisitor(schema.types['A_type'].content) content = [('B1', 'abc'), ('B2', 10), ('B3', False)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B3', False), ('B1', 'abc'), ('B2', 10)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B1', 'abc'), ('B3', False), ('B2', 10)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('B1', 'abc'), ('B1', 'def'), ('B2', 10), ('B3', False)] model.restart() self.assertListEqual( list(model.iter_collapsed_content(content)), [('B1', 'abc'), ('B2', 10), ('B3', False), ('B1', 'def')] ) content = [('B1', 'abc'), ('B2', 10), ('X', None)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) content = [('X', None), ('B1', 'abc'), ('B2', 10), ('B3', False)] model.restart() self.assertListEqual(list(model.iter_collapsed_content(content)), content) class TestModelPaths(unittest.TestCase): def test_distinguishable_paths_one_level(self): group = ModelGroup('sequence', min_occurs=0) group.append(ModelGroup('sequence')) group.append(ModelGroup('sequence')) group[0].append(ParticleMixin()) group[1].append(ParticleMixin()) path1 = [group[0]] path2 = [group[1]] self.assertTrue(distinguishable_paths(path1, path2)) # Disjoined paths self.assertTrue(distinguishable_paths(path1, [])) with self.assertRaises(IndexError): distinguishable_paths([], path2) # path1 cannot be empty path1 = [group, group[0]] path2 = [group, group[1]] self.assertTrue(distinguishable_paths(path1, path2)) group[0].min_occurs = 0 self.assertFalse(distinguishable_paths(path1, path2)) group.max_occurs = 0 self.assertTrue(distinguishable_paths(path1, path2)) def test_distinguishable_paths_two_levels(self): group = ModelGroup('sequence', min_occurs=0) group.append(ModelGroup('choice')) group.append(ModelGroup('choice')) group[0].append(ParticleMixin()) group[0].append(ParticleMixin()) group[1].append(ParticleMixin()) group[1].append(ParticleMixin()) path1 = [group, group[0], group[0][0]] path2 = [group, group[1], group[1][0]] self.assertTrue(distinguishable_paths(path1, path2)) # All univocal subgroups group[0].max_occurs = 2 self.assertFalse(distinguishable_paths(path1, path2)) group[0].max_occurs = 1 group[0].min_occurs = 0 self.assertFalse(distinguishable_paths(path1, path2)) group.max_occurs = None self.assertFalse(distinguishable_paths(path1, path2)) def test_distinguishable_paths_three_levels(self): group = ModelGroup('sequence', min_occurs=0) group.append(ModelGroup('choice')) group.append(ModelGroup('choice')) group[0].append(ModelGroup('choice')) group[1].append(ModelGroup('choice')) group[0][0].append(ParticleMixin()) group[0][0].append(ParticleMixin()) group[1][0].append(ParticleMixin()) group[1][0].append(ParticleMixin()) path1 = [group, group[0], group[0][0], group[0][0][0]] path2 = [group, group[1], group[1][0], group[1][0][0]] self.assertTrue(distinguishable_paths(path1, path2)) # All univocal subgroups group[0][0][1].min_occurs = 0 self.assertFalse(distinguishable_paths(path1, path2)) # All univocal subgroups if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD model groups with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ����������������������xmlschema-1.10.0/tests/validators/test_notations.py�������������������������������������������������0000664�0000000�0000000�00000006575�14211403446�0022527�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchemaParseError from xmlschema.etree import ElementTree from xmlschema.names import XSD_NOTATION from xmlschema.validators import XMLSchema10, XMLSchema11, XsdNotation class TestXsd10Notations(unittest.TestCase): schema_class = XMLSchema10 def test_parse(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation name="content" public="text/html"/> </xs:schema>""") self.assertIn('content', schema.notations) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation name="content"/> </xs:schema>""") self.assertIn("notation must have a 'public' or a 'system' attribute", str(ctx.exception)) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation public="text/html"/> </xs:schema>""") self.assertEqual("missing required attribute 'name'", ctx.exception.message) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation public="text/html"/> </xs:schema>""", validation='skip') self.assertListEqual(schema.all_errors, []) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation public="text/html"/> </xs:schema>""", validation='lax') self.assertEqual(len(schema.all_errors), 2) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="emptyType"/> </xs:schema>""") elem = ElementTree.Element(XSD_NOTATION) with self.assertRaises(XMLSchemaParseError) as ctx: XsdNotation(elem, schema, parent=schema.types['emptyType']) self.assertIn("a notation declaration must be global", str(ctx.exception)) with self.assertRaises(XMLSchemaParseError) as ctx: XsdNotation(elem, schema, parent=None) self.assertIn("a notation must have a 'name' attribute", str(ctx.exception)) def test_properties(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation name="style" public="text/css" system="style.css"/> </xs:schema>""") self.assertEqual(schema.notations['style'].public, "text/css") self.assertEqual(schema.notations['style'].system, "style.css") class TestXsd11Notations(unittest.TestCase): schema_class = XMLSchema11 if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD notations with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_particles.py�������������������������������������������������0000664�0000000�0000000�00000020724�14211403446�0022467�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import os import unittest from xmlschema import XMLSchema10, XMLSchemaParseError from xmlschema.etree import ElementTree from xmlschema.validators.particles import ParticleMixin CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') class TestParticleMixin(unittest.TestCase): @classmethod def setUpClass(cls): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') cls.schema = XMLSchema10(xsd_file) def test_occurs_property(self): self.assertEqual(self.schema.elements['cars'].occurs, (1, 1)) self.assertEqual(self.schema.elements['cars'].type.content[0].occurs, (0, None)) def test_effective_min_occurs_property(self): self.assertEqual(self.schema.elements['cars'].effective_min_occurs, 1) self.assertEqual(self.schema.elements['cars'].type.content[0].effective_min_occurs, 0) def test_effective_max_occurs_property(self): self.assertEqual(self.schema.elements['cars'].effective_max_occurs, 1) self.assertIsNone(self.schema.elements['cars'].type.content[0].effective_max_occurs) def test_is_emptiable(self): self.assertFalse(self.schema.elements['cars'].is_emptiable()) self.assertTrue(self.schema.elements['cars'].type.content[0].is_emptiable()) def test_is_empty(self): self.assertFalse(self.schema.elements['cars'].is_empty()) self.assertFalse(ParticleMixin().is_empty()) self.assertTrue(ParticleMixin(min_occurs=0, max_occurs=0).is_empty()) def test_is_single(self): self.assertTrue(self.schema.elements['cars'].is_single()) self.assertFalse(self.schema.elements['cars'].type.content[0].is_single()) # The base method is used only by xs:any wildcards wildcard = self.schema.meta_schema.types['anyType'].content[0] self.assertFalse(wildcard.is_single()) def test_is_multiple(self): self.assertFalse(self.schema.elements['cars'].is_multiple()) def test_is_ambiguous(self): self.assertFalse(self.schema.elements['cars'].is_ambiguous()) self.assertTrue(self.schema.elements['cars'].type.content[0].is_ambiguous()) def test_is_univocal(self): self.assertTrue(self.schema.elements['cars'].is_univocal()) self.assertFalse(self.schema.elements['cars'].type.content[0].is_univocal()) def test_is_missing(self): self.assertTrue(self.schema.elements['cars'].is_missing(0)) self.assertFalse(self.schema.elements['cars'].is_missing(1)) self.assertFalse(self.schema.elements['cars'].is_missing(2)) self.assertFalse(self.schema.elements['cars'].type.content[0].is_missing(0)) def test_is_over(self): self.assertFalse(self.schema.elements['cars'].is_over(0)) self.assertTrue(self.schema.elements['cars'].is_over(1)) self.assertFalse(self.schema.elements['cars'].type.content[0].is_over(1000)) def test_has_occurs_restriction(self): schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="barType"> <xs:sequence> <xs:element name="node0" /> <xs:element name="node1" minOccurs="0"/> <xs:element name="node2" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="node3" minOccurs="2" maxOccurs="unbounded"/> <xs:element name="node4" minOccurs="2" maxOccurs="10"/> <xs:element name="node5" minOccurs="4" maxOccurs="10"/> <xs:element name="node6" minOccurs="4" maxOccurs="9"/> <xs:element name="node7" minOccurs="1" maxOccurs="9"/> <xs:element name="node8" minOccurs="3" maxOccurs="11"/> <xs:element name="node9" minOccurs="0" maxOccurs="0"/> </xs:sequence> </xs:complexType> </xs:schema>""") xsd_group = schema.types['barType'].content for k in range(9): self.assertTrue( xsd_group[k].has_occurs_restriction(xsd_group[k]), msg="Fail for node%d" % k ) self.assertTrue(xsd_group[0].has_occurs_restriction(xsd_group[1])) self.assertFalse(xsd_group[1].has_occurs_restriction(xsd_group[0])) self.assertTrue(xsd_group[3].has_occurs_restriction(xsd_group[2])) self.assertFalse(xsd_group[2].has_occurs_restriction(xsd_group[1])) self.assertFalse(xsd_group[2].has_occurs_restriction(xsd_group[3])) self.assertTrue(xsd_group[4].has_occurs_restriction(xsd_group[3])) self.assertTrue(xsd_group[4].has_occurs_restriction(xsd_group[2])) self.assertFalse(xsd_group[4].has_occurs_restriction(xsd_group[5])) self.assertTrue(xsd_group[5].has_occurs_restriction(xsd_group[4])) self.assertTrue(xsd_group[6].has_occurs_restriction(xsd_group[5])) self.assertFalse(xsd_group[5].has_occurs_restriction(xsd_group[6])) self.assertFalse(xsd_group[7].has_occurs_restriction(xsd_group[6])) self.assertFalse(xsd_group[5].has_occurs_restriction(xsd_group[7])) self.assertTrue(xsd_group[6].has_occurs_restriction(xsd_group[7])) self.assertFalse(xsd_group[7].has_occurs_restriction(xsd_group[8])) self.assertFalse(xsd_group[8].has_occurs_restriction(xsd_group[7])) self.assertTrue(xsd_group[9].has_occurs_restriction(xsd_group[1])) self.assertTrue(xsd_group[9].has_occurs_restriction(xsd_group[2])) def test_default_parse_error(self): with self.assertRaises(ValueError) as ctx: ParticleMixin().parse_error('unexpected error') self.assertEqual(str(ctx.exception), 'unexpected error') def test_parse_particle(self): schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""") xsd_element = schema.elements['root'] elem = ElementTree.Element('root', minOccurs='1', maxOccurs='1') xsd_element._parse_particle(elem) elem = ElementTree.Element('root', minOccurs='2', maxOccurs='1') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("maxOccurs must be 'unbounded' or greater than minOccurs", str(ctx.exception)) elem = ElementTree.Element('root', minOccurs='-1', maxOccurs='1') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("minOccurs value must be a non negative integer", str(ctx.exception)) elem = ElementTree.Element('root', minOccurs='1', maxOccurs='-1') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("maxOccurs must be 'unbounded' or greater than minOccurs", str(ctx.exception)) elem = ElementTree.Element('root', minOccurs='1', maxOccurs='none') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("maxOccurs value must be a non negative integer or 'unbounded'", str(ctx.exception)) elem = ElementTree.Element('root', minOccurs='2') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("minOccurs must be lesser or equal than maxOccurs", str(ctx.exception)) elem = ElementTree.Element('root', minOccurs='none') with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_particle(elem) self.assertIn("minOccurs value is not an integer value", str(ctx.exception)) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD particles with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ��������������������������������������������xmlschema-1.10.0/tests/validators/test_schemas.py���������������������������������������������������0000664�0000000�0000000�00000117661�14211403446�0022133�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import logging import tempfile import warnings import pathlib import pickle import platform import glob import os import re from textwrap import dedent from xmlschema import XMLSchemaParseError, XMLSchemaIncludeWarning, XMLSchemaImportWarning from xmlschema.names import XML_NAMESPACE, LOCATION_HINTS, SCHEMAS_DIR, XSD_ELEMENT, XSI_TYPE from xmlschema.etree import etree_element from xmlschema.validators import XMLSchemaBase, XMLSchema10, XMLSchema11, \ XsdGlobals, Xsd11Attribute from xmlschema.testing import SKIP_REMOTE_TESTS, XsdValidatorTestCase from xmlschema.validators.schemas import logger class CustomXMLSchema(XMLSchema10): pass class TestXMLSchema10(XsdValidatorTestCase): TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') maxDiff = None class CustomXMLSchema(XMLSchema10): pass def test_schema_validation(self): schema = self.schema_class(self.vh_xsd_file) self.assertEqual(schema.validation, 'strict') schema = self.schema_class(self.vh_xsd_file, validation='lax') self.assertEqual(schema.validation, 'lax') schema = self.schema_class(self.vh_xsd_file, validation='skip') self.assertEqual(schema.validation, 'skip') with self.assertRaises(ValueError): self.schema_class(self.vh_xsd_file, validation='none') def test_schema_string_repr(self): schema = self.schema_class(self.vh_xsd_file) tmpl = "%s(name='vehicles.xsd', namespace='http://example.com/vehicles')" self.assertEqual(str(schema), tmpl % self.schema_class.__name__) def test_schema_copy(self): schema = self.vh_schema.copy() self.assertNotEqual(id(self.vh_schema), id(schema)) self.assertNotEqual(id(self.vh_schema.namespaces), id(schema.namespaces)) self.assertNotEqual(id(self.vh_schema.maps), id(schema.maps)) def test_schema_location_hints(self): with warnings.catch_warnings(record=True): warnings.simplefilter("always") schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlschema.test/ns schema.xsd"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.schema_location, [("http://xmlschema.test/ns", "schema.xsd")]) self.assertIsNone(schema.no_namespace_schema_location) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.schema_location, []) self.assertEqual(schema.no_namespace_schema_location, 'schema.xsd') def test_target_prefix(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.target_prefix, '') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://xmlschema.test/ns" targetNamespace="http://xmlschema.test/ns"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.target_prefix, 'tns') def test_builtin_types(self): self.assertIn('string', self.schema_class.builtin_types()) with self.assertRaises(RuntimeError): self.schema_class.meta_schema.builtin_types() def test_resolve_qname(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.resolve_qname('xs:element'), XSD_ELEMENT) self.assertEqual(schema.resolve_qname('xsi:type'), XSI_TYPE) self.assertEqual(schema.resolve_qname(XSI_TYPE), XSI_TYPE) self.assertEqual(schema.resolve_qname('element'), 'element') self.assertRaises(ValueError, schema.resolve_qname, '') self.assertRaises(ValueError, schema.resolve_qname, 'xsi:a type ') self.assertRaises(ValueError, schema.resolve_qname, 'xml::lang') def test_global_group_definitions(self): schema = self.check_schema(""" <xs:group name="wrong_child"> <xs:element name="foo"/> </xs:group>""", validation='lax') self.assertEqual(len(schema.errors), 1) self.check_schema('<xs:group name="empty" />', XMLSchemaParseError) self.check_schema('<xs:group name="empty"><xs:annotation/></xs:group>', XMLSchemaParseError) def test_wrong_includes_and_imports(self): with warnings.catch_warnings(record=True) as context: warnings.simplefilter("always") self.check_schema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns"> <xs:include schemaLocation="example.xsd" /> <xs:import schemaLocation="example.xsd" /> <xs:redefine schemaLocation="example.xsd"/> <xs:import namespace="http://missing.example.test/" /> <xs:import/> </xs:schema> """) self.assertEqual(len(context), 3, "Wrong number of include/import warnings") self.assertEqual(context[0].category, XMLSchemaIncludeWarning) self.assertEqual(context[1].category, XMLSchemaIncludeWarning) self.assertEqual(context[2].category, XMLSchemaImportWarning) self.assertTrue(str(context[0].message).startswith("Include")) self.assertTrue(str(context[1].message).startswith("Redefine")) self.assertTrue(str(context[2].message).startswith("Import of namespace")) def test_wrong_references(self): # Wrong namespace for element type's reference self.check_schema(""" <xs:element name="dimension" type="xs:dimensionType"/> <xs:simpleType name="dimensionType"> <xs:restriction base="xs:short"/> </xs:simpleType> """, XMLSchemaParseError) def test_annotations(self): schema = self.check_schema(""" <xs:element name='foo'> <xs:annotation /> </xs:element>""") xsd_element = schema.elements['foo'] self.assertIsNone(xsd_element._annotation) # lazy annotation self.assertIsNotNone(xsd_element.annotation) self.assertIs(xsd_element.annotation, xsd_element._annotation) self.check_schema(""" <xs:simpleType name='Magic'> <xs:annotation /> <xs:annotation /> <xs:restriction base='xs:string'> <xs:enumeration value='A'/> </xs:restriction> </xs:simpleType>""", XMLSchemaParseError) schema = self.check_schema(""" <xs:simpleType name='Magic'> <xs:annotation> <xs:documentation> stuff </xs:documentation> </xs:annotation> <xs:restriction base='xs:string'> <xs:enumeration value='A'/> </xs:restriction> </xs:simpleType>""") xsd_type = schema.types["Magic"] self.assertIsNotNone(xsd_type._annotation) # xs:simpleType annotations are not lazy parsed self.assertEqual(str(xsd_type.annotation), ' stuff ') def test_annotation_string(self): schema = self.check_schema(""" <xs:element name='A'> <xs:annotation> <xs:documentation>A element info</xs:documentation> </xs:annotation> </xs:element> <xs:element name='B'> <xs:annotation> <xs:documentation>B element extended info, line1</xs:documentation> <xs:documentation>B element extended info, line2</xs:documentation> </xs:annotation> </xs:element>""") xsd_element = schema.elements['A'] self.assertEqual(str(xsd_element.annotation), 'A element info') self.assertEqual(repr(xsd_element.annotation), "XsdAnnotation('A element info')") xsd_element = schema.elements['B'] self.assertEqual(str(xsd_element.annotation), 'B element extended info, line1\nB element extended info, line2') self.assertEqual(repr(xsd_element.annotation), "XsdAnnotation('B element extended info, line1\\nB element')") def test_schema_annotations(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""")) self.assertIsNone(schema._annotations) annotations = schema.annotations self.assertListEqual(annotations, []) self.assertIs(annotations, schema.annotations) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:annotation> <xs:documentation>First annotation</xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation>Second annotation</xs:documentation> </xs:annotation> <xs:element name="root"/> <xs:annotation> <xs:documentation>Third annotation</xs:documentation> </xs:annotation> </xs:schema>""")) self.assertIsNone(schema._annotations) annotations = schema.annotations self.assertEqual(len(annotations), 3) self.assertEqual(repr(annotations[0]), "XsdAnnotation('First annotation')") self.assertEqual(repr(annotations[1]), "XsdAnnotation('Second annotation')") self.assertEqual(repr(annotations[2]), "XsdAnnotation('Third annotation')") self.assertIs(annotations, schema.annotations) def test_base_schemas(self): xsd_file = os.path.join(SCHEMAS_DIR, 'XML/xml_minimal.xsd') schema = self.schema_class(xsd_file) self.assertEqual(schema.target_namespace, XML_NAMESPACE) def test_root_elements(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"/>""")) self.assertEqual(schema.root_elements, []) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" /> </xs:schema>""")) self.assertEqual(schema.root_elements, [schema.elements['root']]) # Test issue #107 fix schema = self.schema_class(dedent("""\ <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root1" type="root"/> <xs:element name="root2" type="root"/> <xs:complexType name="root"> <xs:sequence> <xs:element name="elementWithNoType"/> </xs:sequence> </xs:complexType> </xs:schema>""")) self.assertEqual(set(schema.root_elements), {schema.elements['root1'], schema.elements['root2']}) def test_simple_types(self): self.assertListEqual(self.vh_schema.simple_types, []) self.assertGreater(len(self.st_schema.simple_types), 20) def test_complex_types(self): self.assertListEqual(self.vh_schema.complex_types, [self.vh_schema.types['vehicleType']]) def test_is_restriction_method(self): # Test issue #111 fix schema = self.schema_class(source=self.casepath('issues/issue_111/issue_111.xsd')) extended_header_def = schema.types['extendedHeaderDef'] self.assertTrue(extended_header_def.is_derived(schema.types['blockDef'])) @unittest.skipIf(SKIP_REMOTE_TESTS, "Remote networks are not accessible.") def test_remote_schemas_loading(self): col_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/" "tests/test_cases/examples/collection/collection.xsd", timeout=300) self.assertTrue(isinstance(col_schema, self.schema_class)) vh_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/" "tests/test_cases/examples/vehicles/vehicles.xsd", timeout=300) self.assertTrue(isinstance(vh_schema, self.schema_class)) def test_schema_defuse(self): vh_schema = self.schema_class(self.vh_xsd_file, defuse='always') self.assertIsInstance(vh_schema.root, etree_element) for schema in vh_schema.maps.iter_schemas(): self.assertIsInstance(schema.root, etree_element) def test_logging(self): self.schema_class(self.vh_xsd_file, loglevel=logging.ERROR) self.assertEqual(logger.level, logging.WARNING) with self.assertLogs('xmlschema', level='INFO') as ctx: self.schema_class(self.vh_xsd_file, loglevel=logging.INFO) self.assertEqual(logger.level, logging.WARNING) self.assertEqual(len(ctx.output), 7) self.assertIn("INFO:xmlschema:Include schema from 'types.xsd'", ctx.output) self.assertIn("INFO:xmlschema:Resource 'types.xsd' is already loaded", ctx.output) with self.assertLogs('xmlschema', level='DEBUG') as ctx: self.schema_class(self.vh_xsd_file, loglevel=logging.DEBUG) self.assertEqual(logger.level, logging.WARNING) self.assertEqual(len(ctx.output), 19) self.assertIn("INFO:xmlschema:Include schema from 'cars.xsd'", ctx.output) self.assertIn("INFO:xmlschema:Resource 'cars.xsd' is already loaded", ctx.output) self.assertIn("DEBUG:xmlschema:Schema targetNamespace is " "'http://example.com/vehicles'", ctx.output) self.assertIn("INFO:xmlschema:Resource 'cars.xsd' is already loaded", ctx.output) # With string argument with self.assertRaises(ValueError) as ctx: self.schema_class(self.vh_xsd_file, loglevel='all') self.assertEqual(str(ctx.exception), "'all' is not a valid loglevel") with self.assertLogs('xmlschema', level='INFO') as ctx: self.schema_class(self.vh_xsd_file, loglevel='INFO') self.assertEqual(len(ctx.output), 7) with self.assertLogs('xmlschema', level='INFO') as ctx: self.schema_class(self.vh_xsd_file, loglevel=' Info ') self.assertEqual(len(ctx.output), 7) def test_target_namespace(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(schema.target_namespace, 'http://xmlschema.test/ns') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(schema.target_namespace, '') with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace=""> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(ctx.exception.message, "the attribute 'targetNamespace' cannot be an empty string") def test_block_default(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" blockDefault="extension restriction "> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(schema.block_default, 'extension restriction ') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" blockDefault="#all"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(set(schema.block_default.split()), {'substitution', 'extension', 'restriction'}) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" blockDefault="all">> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(ctx.exception.message, "wrong value 'all' for attribute 'blockDefault'") with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" blockDefault="#all restriction">> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(ctx.exception.message, "wrong value '#all restriction' for attribute 'blockDefault'") def test_final_default(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" finalDefault="extension restriction "> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(schema.final_default, 'extension restriction ') schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" finalDefault="#all"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(set(schema.final_default.split()), {'list', 'union', 'extension', 'restriction'}) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" finalDefault="all">> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(ctx.exception.message, "wrong value 'all' for attribute 'finalDefault'") def test_use_fallback(self): source = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""") schema = self.schema_class(source) self.assertEqual(schema.fallback_locations, LOCATION_HINTS) schema = self.schema_class(source, use_fallback=False) self.assertEqual(schema.fallback_locations, {}) def test_global_maps(self): source = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""") col_schema = self.schema_class(self.col_xsd_file) with self.assertRaises(TypeError) as ctx: self.schema_class(self.col_schema, global_maps=col_schema) self.assertIn("'global_maps' argument must be", str(ctx.exception)) schema = self.schema_class(source, global_maps=col_schema.maps) self.assertIs(col_schema.maps, schema.maps) def test_version_control(self): schema = self.schema_class(dedent(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:attribute name="a" use="required"/> <xs:assert test="@a > 300" vc:minVersion="1.1" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"/> </xs:complexType> </xs:element> </xs:schema>""")) self.assertEqual(len(schema.root[0][0]), 1 if schema.XSD_VERSION == '1.0' else 2) schema = self.schema_class(dedent(""" <xs:schema vc:minVersion="1.1" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual(len(schema.root), 0 if schema.XSD_VERSION == '1.0' else 1) def test_xsd_version_compatibility_property(self): self.assertEqual(self.vh_schema.xsd_version, self.vh_schema.XSD_VERSION) def test_explicit_locations(self): source = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""") locations = {'http://example.com/vehicles': self.vh_xsd_file} schema = self.schema_class(source, locations=locations) self.assertEqual(len(schema.maps.namespaces['http://example.com/vehicles']), 4) def test_use_meta_property(self): self.assertTrue(self.vh_schema.use_meta) self.assertTrue(self.col_schema.use_meta) meta_schema = self.schema_class.meta_schema schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="foo"/> </xs:schema>"""), use_meta=False) self.assertIsNot(meta_schema, schema.meta_schema) self.assertFalse(schema.use_meta) def test_other_schema_root_attributes(self): self.assertIsNone(self.vh_schema.id) self.assertIsNone(self.vh_schema.version) schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" id="foo" version="2.0"> <xs:element name="foo"/> </xs:schema>""")) self.assertEqual(schema.id, 'foo') self.assertEqual(schema.version, '2.0') def test_change_maps_attribute(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""")) with self.assertRaises(ValueError) as ctx: schema.meta_schema.maps = XsdGlobals(schema, schema.validation) self.assertEqual(str(ctx.exception), "cannot change the global maps instance of a meta-schema") self.assertTrue(schema.built) maps, schema.maps = schema.maps, XsdGlobals(schema, schema.validation) self.assertIsNot(maps, schema.maps) self.assertFalse(schema.built) schema.maps = maps self.assertTrue(schema.built) def test_listed_and_reversed_elements(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elem1"/> <xs:element name="elem2"/> <xs:element name="elem3"/> </xs:schema>""")) elements = list(schema) self.assertListEqual(elements, [schema.elements['elem1'], schema.elements['elem2'], schema.elements['elem3']]) elements.reverse() self.assertListEqual(elements, list(reversed(schema))) def test_multi_schema_initialization(self): source1 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elem1"/> </xs:schema>""") source2 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elem2"/> </xs:schema>""") source3 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elem3"/> </xs:schema>""") schema = self.schema_class([source1, source2, source3]) self.assertEqual(len(schema.elements), 3) self.assertEqual(len(schema.maps.namespaces['']), 3) self.assertIs(schema.elements['elem1'].schema, schema) self.assertIs(schema.elements['elem2'].schema, schema.maps.namespaces[''][1]) self.assertIs(schema.elements['elem3'].schema, schema.maps.namespaces[''][2]) with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class([source1, source2, source2]) self.assertIn("global element with name='elem2' is already defined", str(ec.exception)) source1 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns"> <xs:element name="elem1"/> </xs:schema>""") schema = self.schema_class([source1, source2]) self.assertEqual(len(schema.elements), 2) self.assertEqual(len(schema.maps.namespaces['http://xmlschema.test/ns']), 2) self.assertIs(schema.elements['elem1'].schema, schema) self.assertIs(schema.elements['elem2'].schema, schema.maps.namespaces['http://xmlschema.test/ns'][1]) def test_add_schema(self): source1 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns"> <xs:element name="elem1"/> </xs:schema>""") source2 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="elem2"/> </xs:schema>""") source3 = dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xmlschema.test/ns1"> <xs:element name="elem3"/> </xs:schema>""") schema = self.schema_class(source1) schema.add_schema(source2, build=True) self.assertEqual(len(schema.elements), 1) self.assertEqual(len(schema.maps.namespaces['http://xmlschema.test/ns']), 1) self.assertEqual(len(schema.maps.namespaces['']), 1) # Less checks on duplicate objects for schemas added after the build schema.add_schema(source2, build=True) self.assertEqual(len(schema.maps.namespaces['']), 2) self.assertTrue(schema.maps.built) with self.assertRaises(XMLSchemaParseError) as ec: schema.maps.clear() schema.build() self.assertIn("global element with name='elem2' is already defined", str(ec.exception)) schema = self.schema_class(source1) schema.add_schema(source2, namespace='http://xmlschema.test/ns', build=True) self.assertEqual(len(schema.maps.namespaces['http://xmlschema.test/ns']), 2) # Need a rebuild to add elem2 from added schema ... self.assertEqual(len(schema.elements), 1) schema.maps.clear() schema.build() self.assertEqual(len(schema.elements), 2) # ... so is better to build after sources additions schema = self.schema_class(source1, build=False) schema.add_schema(source2, namespace='http://xmlschema.test/ns') schema.build() self.assertEqual(len(schema.elements), 2) # Adding other namespaces do not require rebuild schema3 = schema.add_schema(source3, build=True) self.assertEqual(len(schema.maps.namespaces['http://xmlschema.test/ns1']), 1) self.assertEqual(len(schema3.elements), 1) def test_export_errors__issue_187(self): with self.assertRaises(ValueError) as ctx: self.vh_schema.export(target=self.vh_dir) self.assertIn("target directory", str(ctx.exception)) self.assertIn("is not empty", str(ctx.exception)) with self.assertRaises(ValueError) as ctx: self.vh_schema.export(target=self.vh_xsd_file) self.assertIn("target", str(ctx.exception)) self.assertIn("is not a directory", str(ctx.exception)) with self.assertRaises(ValueError) as ctx: self.vh_schema.export(target=self.vh_xsd_file + '/target') self.assertIn("target parent", str(ctx.exception)) self.assertIn("is not a directory", str(ctx.exception)) with tempfile.TemporaryDirectory() as dirname: with self.assertRaises(ValueError) as ctx: self.vh_schema.export(target=dirname + 'subdir/target') self.assertIn("target parent directory", str(ctx.exception)) self.assertIn("does not exist", str(ctx.exception)) def test_export_same_directory__issue_187(self): with tempfile.TemporaryDirectory() as dirname: self.vh_schema.export(target=dirname) for filename in os.listdir(dirname): with pathlib.Path(dirname).joinpath(filename).open() as fp: exported_schema = fp.read() with pathlib.Path(self.vh_dir).joinpath(filename).open() as fp: original_schema = fp.read() if platform.system() == 'Windows': exported_schema = re.sub(r'\s+', '', exported_schema) original_schema = re.sub(r'\s+', '', original_schema) self.assertEqual(exported_schema, original_schema) self.assertFalse(os.path.isdir(dirname)) def test_export_another_directory__issue_187(self): vh_schema_file = self.casepath('issues/issue_187/issue_187_1.xsd') vh_schema = self.schema_class(vh_schema_file) with tempfile.TemporaryDirectory() as dirname: vh_schema.export(target=dirname) path = pathlib.Path(dirname).joinpath('examples/vehicles/*.xsd') for filename in glob.iglob(pathname=str(path)): with pathlib.Path(dirname).joinpath(filename).open() as fp: exported_schema = fp.read() basename = os.path.basename(filename) with pathlib.Path(self.vh_dir).joinpath(basename).open() as fp: original_schema = fp.read() if platform.system() == 'Windows': exported_schema = re.sub(r'\s+', '', exported_schema) original_schema = re.sub(r'\s+', '', original_schema) self.assertEqual(exported_schema, original_schema) with pathlib.Path(dirname).joinpath('issue_187_1.xsd').open() as fp: exported_schema = fp.read() with open(vh_schema_file) as fp: original_schema = fp.read() if platform.system() == 'Windows': exported_schema = re.sub(r'\s+', '', exported_schema) original_schema = re.sub(r'\s+', '', original_schema) self.assertNotEqual(exported_schema, original_schema) self.assertEqual( exported_schema, original_schema.replace('../..', dirname.replace('\\', '/')) ) self.assertFalse(os.path.isdir(dirname)) @unittest.skipIf(SKIP_REMOTE_TESTS, "Remote networks are not accessible.") def test_export_remote__issue_187(self): vh_schema_file = self.casepath('issues/issue_187/issue_187_2.xsd') vh_schema = self.schema_class(vh_schema_file) with tempfile.TemporaryDirectory() as dirname: vh_schema.export(target=dirname) with pathlib.Path(dirname).joinpath('issue_187_2.xsd').open() as fp: exported_schema = fp.read() with open(vh_schema_file) as fp: original_schema = fp.read() if platform.system() == 'Windows': exported_schema = re.sub(r'\s+', '', exported_schema) original_schema = re.sub(r'\s+', '', original_schema) self.assertEqual(exported_schema, original_schema) self.assertFalse(os.path.isdir(dirname)) with tempfile.TemporaryDirectory() as dirname: vh_schema.export(target=dirname, save_remote=True) path = pathlib.Path(dirname).joinpath('brunato/xmlschema/master/tests/test_cases/' 'examples/vehicles/*.xsd') for filename in glob.iglob(pathname=str(path)): with pathlib.Path(dirname).joinpath(filename).open() as fp: exported_schema = fp.read() basename = os.path.basename(filename) with pathlib.Path(self.vh_dir).joinpath(basename).open() as fp: original_schema = fp.read() self.assertEqual(exported_schema, original_schema) with pathlib.Path(dirname).joinpath('issue_187_2.xsd').open() as fp: exported_schema = fp.read() with open(vh_schema_file) as fp: original_schema = fp.read() if platform.system() == 'Windows': exported_schema = re.sub(r'\s+', '', exported_schema) original_schema = re.sub(r'\s+', '', original_schema) self.assertNotEqual(exported_schema, original_schema) self.assertEqual( exported_schema, original_schema.replace('https://raw.githubusercontent.com', dirname.replace('\\', '/') + '/raw.githubusercontent.com') ) self.assertFalse(os.path.isdir(dirname)) def test_pickling_subclassed_schema__issue_263(self): cases_dir = pathlib.Path(__file__).parent.parent schema_file = cases_dir.joinpath('test_cases/examples/vehicles/vehicles.xsd') xml_file = cases_dir.joinpath('test_cases/examples/vehicles/vehicles.xml') schema = self.CustomXMLSchema(str(schema_file)) self.assertTrue(schema.is_valid(str(xml_file))) self.assertIs(self.schema_class.meta_schema, schema.meta_schema) self.assertNotIn(schema.meta_schema.__class__.__name__, globals()) s = pickle.dumps(schema) _schema = pickle.loads(s) self.assertTrue(_schema.is_valid(str(xml_file))) class CustomLocalXMLSchema(self.schema_class): pass schema = CustomLocalXMLSchema(str(schema_file)) self.assertTrue(schema.is_valid(str(xml_file))) with self.assertRaises((pickle.PicklingError, AttributeError)) as ec: pickle.dumps(schema) self.assertIn("Can't pickle", str(ec.exception)) def test_old_subclassing_attribute(self): with warnings.catch_warnings(record=True) as ctx: warnings.simplefilter("always") class OldXMLSchema10(XMLSchema10): BUILDERS = { 'attribute_class': Xsd11Attribute, } self.assertEqual(len(ctx), 1, "Expected one import warning") self.assertIn("'BUILDERS' will be removed in v2.0", str(ctx[0].message)) self.assertIs(OldXMLSchema10.xsd_attribute_class, Xsd11Attribute) name = OldXMLSchema10.meta_schema.__class__.__name__ self.assertEqual(name, 'MetaXMLSchema10') self.assertNotIn(name, globals()) def test_default_namespace_mapping__issue_266(self): schema_file = self.casepath('issues/issue_266/issue_266b-1.xsd') with self.assertRaises(XMLSchemaParseError) as ec: self.schema_class(schema_file) error_message = str(ec.exception) self.assertIn("the QName 'testAttribute3' is mapped to no namespace", error_message) self.assertIn("requires that there is an xs:import statement", error_message) class TestXMLSchema11(TestXMLSchema10): schema_class = XMLSchema11 class CustomXMLSchema(XMLSchema11): pass def test_default_attributes(self): schema = self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" defaultAttributes="attrs"> <xs:element name="root"/> <xs:attributeGroup name="attrs"> <xs:attribute name="a"/> </xs:attributeGroup> </xs:schema>""")) self.assertIs(schema.default_attributes, schema.attribute_groups['attrs']) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" defaultAttributes="attrs"> <xs:element name="root"/> </xs:schema>""")) self.assertIn("'attrs' doesn't match an attribute group", ctx.exception.message) with self.assertRaises(XMLSchemaParseError) as ctx: self.schema_class(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" defaultAttributes="x:attrs"> <xs:element name="root"/> </xs:schema>""")) self.assertEqual("prefix 'x' not found in namespace map", ctx.exception.message) class TestXMLSchemaMeta(unittest.TestCase): def test_wrong_version(self): with self.assertRaises(ValueError) as ctx: class XMLSchema12(XMLSchemaBase): XSD_VERSION = '1.2' meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.1/XMLSchema.xsd') assert issubclass(XMLSchema12, XMLSchemaBase) self.assertEqual(str(ctx.exception), "XSD_VERSION must be '1.0' or '1.1'") def test_from_schema_class(self): class XMLSchema11Bis(XMLSchema11): pass self.assertTrue(issubclass(XMLSchema11Bis, XMLSchemaBase)) def test_dummy_validator_class(self): class DummySchema(XMLSchemaBase): XSD_VERSION = '1.1' meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.1/XMLSchema.xsd') self.assertTrue(issubclass(DummySchema, XMLSchemaBase)) def test_subclass_but_no_replace_meta_schema(self): class CustomXMLSchema10(XMLSchema10): pass self.assertIsInstance(CustomXMLSchema10.meta_schema, XMLSchemaBase) self.assertIs(CustomXMLSchema10.meta_schema, XMLSchema10.meta_schema) name = CustomXMLSchema10.meta_schema.__class__.__name__ self.assertEqual(name, 'MetaXMLSchema10') self.assertNotIn(name, globals()) def test_subclass_and_replace_meta_schema(self): class CustomXMLSchema10(XMLSchema10): meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.0/XMLSchema.xsd') self.assertIsInstance(CustomXMLSchema10.meta_schema, XMLSchemaBase) self.assertIsNot(CustomXMLSchema10.meta_schema, XMLSchema10.meta_schema) name = CustomXMLSchema10.meta_schema.__class__.__name__ self.assertEqual(name, 'MetaCustomXMLSchema10') self.assertIn(name, globals()) bases = CustomXMLSchema10.meta_schema.__class__.__bases__ self.assertEqual(bases, (XMLSchema10.meta_schema.__class__,)) def test_subclass_and_create_base_meta_schema(self): class CustomXMLSchema10(XMLSchemaBase): meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.0/XMLSchema.xsd') self.assertIsInstance(CustomXMLSchema10.meta_schema, XMLSchemaBase) self.assertIsNot(CustomXMLSchema10.meta_schema, XMLSchema10.meta_schema) name = CustomXMLSchema10.meta_schema.__class__.__name__ self.assertEqual(name, 'MetaCustomXMLSchema10') self.assertIn(name, globals()) bases = CustomXMLSchema10.meta_schema.__class__.__bases__ self.assertEqual(bases, (XMLSchemaBase,)) if __name__ == '__main__': header_template = "Test xmlschema's schema classes with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_simple_types.py����������������������������������������������0000664�0000000�0000000�00000024110�14211403446�0023207�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchemaParseError, XMLSchemaValidationError from xmlschema.names import XSD_LIST, XSD_UNION from xmlschema.validators import XMLSchema11 from xmlschema.testing import XsdValidatorTestCase class TestXsdSimpleTypes(XsdValidatorTestCase): def test_simple_types(self): # Issue #54: set list or union schema element. xs = self.check_schema(""" <xs:simpleType name="test_list"> <xs:annotation/> <xs:list itemType="xs:string"/> </xs:simpleType> <xs:simpleType name="test_union"> <xs:annotation/> <xs:union memberTypes="xs:string xs:integer xs:boolean"/> </xs:simpleType> """) xs.types['test_list'].elem = xs.root[0] # elem.tag == 'simpleType' self.assertEqual(xs.types['test_list'].elem.tag, XSD_LIST) xs.types['test_union'].elem = xs.root[1] # elem.tag == 'simpleType' self.assertEqual(xs.types['test_union'].elem.tag, XSD_UNION) def test_variety_property(self): schema = self.check_schema(""" <xs:simpleType name="atomicType"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="listType"> <xs:list itemType="xs:string"/> </xs:simpleType> <xs:simpleType name="listType2"> <xs:restriction base="listType"/> </xs:simpleType> <xs:simpleType name="unionType"> <xs:union memberTypes="xs:string xs:integer xs:boolean"/> </xs:simpleType> <xs:simpleType name="unionType2"> <xs:restriction base="unionType"/> </xs:simpleType> """) self.assertEqual(schema.types['atomicType'].variety, 'atomic') self.assertEqual(schema.types['listType'].variety, 'list') self.assertEqual(schema.types['listType2'].variety, 'list') self.assertEqual(schema.types['unionType'].variety, 'union') self.assertEqual(schema.types['unionType2'].variety, 'union') def test_final_attribute(self): self.check_schema(""" <xs:simpleType name="aType" final="list restriction"> <xs:restriction base="xs:string"/> </xs:simpleType> """) def test_facets(self): # Issue #55 and a near error (derivation from xs:integer) self.check_schema(""" <xs:simpleType name="dtype"> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="3" /> <xs:totalDigits value="20" /> </xs:restriction> </xs:simpleType> <xs:simpleType name="ntype"> <xs:restriction base="dtype"> <xs:totalDigits value="3" /> <xs:fractionDigits value="1" /> </xs:restriction> </xs:simpleType> """) self.check_schema(""" <xs:simpleType name="dtype"> <xs:restriction base="xs:integer"> <xs:fractionDigits value="3" /> <!-- <<< value must be 0 --> <xs:totalDigits value="20" /> </xs:restriction> </xs:simpleType> """, XMLSchemaParseError) # Issue #56 self.check_schema(""" <xs:simpleType name="mlengthparent"> <xs:restriction base="xs:string"> <xs:maxLength value="200"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="mlengthchild"> <xs:restriction base="mlengthparent"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> """) def test_union_restrictions(self): # Wrong union restriction (not admitted facets, see issue #67) self.check_schema(r""" <xs:simpleType name="Percentage"> <xs:restriction base="Integer"> <xs:minInclusive value="0"/> <xs:maxInclusive value="100"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Integer"> <xs:union memberTypes="xs:int IntegerString"/> </xs:simpleType> <xs:simpleType name="IntegerString"> <xs:restriction base="xs:string"> <xs:pattern value="-?[0-9]+(\.[0-9]+)?%"/> </xs:restriction> </xs:simpleType> """, XMLSchemaParseError) def test_date_time_facets(self): self.check_schema(""" <xs:simpleType name="restricted_date"> <xs:restriction base="xs:date"> <xs:minInclusive value="1900-01-01"/> <xs:maxInclusive value="2030-12-31"/> </xs:restriction> </xs:simpleType>""") self.check_schema(""" <xs:simpleType name="restricted_year"> <xs:restriction base="xs:gYear"> <xs:minInclusive value="1900"/> <xs:maxInclusive value="2030"/> </xs:restriction> </xs:simpleType>""") def test_is_empty(self): schema = self.check_schema(""" <xs:simpleType name="emptyType1"> <xs:restriction base="xs:string"> <xs:maxLength value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="emptyType2"> <xs:restriction base="xs:string"> <xs:length value="0"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="emptyType3"> <xs:restriction base="xs:string"> <xs:enumeration value=""/> </xs:restriction> </xs:simpleType> <xs:simpleType name="notEmptyType1"> <xs:restriction base="xs:string"> <xs:enumeration value=" "/> </xs:restriction> </xs:simpleType>""") self.assertTrue(schema.types['emptyType1'].is_empty()) self.assertTrue(schema.types['emptyType2'].is_empty()) self.assertTrue(schema.types['emptyType3'].is_empty()) self.assertFalse(schema.types['notEmptyType1'].is_empty()) class TestXsd11SimpleTypes(TestXsdSimpleTypes): schema_class = XMLSchema11 def test_explicit_timezone_facet(self): schema = self.check_schema(""" <xs:simpleType name='opt-tz-date'> <xs:restriction base='xs:date'> <xs:explicitTimezone value='optional'/> </xs:restriction> </xs:simpleType> <xs:simpleType name='req-tz-date'> <xs:restriction base='xs:date'> <xs:explicitTimezone value='required'/> </xs:restriction> </xs:simpleType> <xs:simpleType name='no-tz-date'> <xs:restriction base='xs:date'> <xs:explicitTimezone value='prohibited'/> </xs:restriction> </xs:simpleType> """) self.assertTrue(schema.types['req-tz-date'].is_valid('2002-10-10-05:00')) self.assertTrue(schema.types['req-tz-date'].is_valid('2002-10-10Z')) self.assertFalse(schema.types['req-tz-date'].is_valid('2002-10-10')) def test_assertion_facet(self): self.check_schema(""" <xs:simpleType name='DimensionType'> <xs:restriction base='xs:integer'> <xs:assertion test='string-length($value) < 2'/> </xs:restriction> </xs:simpleType>""") schema = self.check_schema(""" <xs:simpleType name='MeasureType'> <xs:restriction base='xs:integer'> <xs:assertion test='$value > 0'/> </xs:restriction> </xs:simpleType>""") self.assertTrue(schema.types['MeasureType'].is_valid('10')) self.assertFalse(schema.types['MeasureType'].is_valid('-1.5')) # Schema is valid but data value can't be compared with the string on the right schema = self.check_schema(""" <xs:simpleType name='RestrictedDateTimeType'> <xs:restriction base='xs:dateTime'> <xs:assertion test="$value > '1999-12-31T23:59:59'"/> </xs:restriction> </xs:simpleType>""") self.assertFalse(schema.types['RestrictedDateTimeType'].is_valid('2000-01-01T12:00:00')) # '>' not supported between instances of 'DateTime' and 'str' with self.assertRaises(XMLSchemaValidationError): schema.types['RestrictedDateTimeType'].validate('2000-01-01T12:00:00') schema = self.check_schema(""" <xs:simpleType name='RestrictedDateTimeType'> <xs:restriction base='xs:dateTime'> <xs:assertion test="$value > xs:dateTime('1999-12-31T23:59:59')"/> </xs:restriction> </xs:simpleType>""") self.assertTrue(schema.types['RestrictedDateTimeType'].is_valid('2000-01-01T12:00:00')) schema = self.check_schema(""" <xs:simpleType name="Percentage"> <xs:restriction base="xs:integer"> <xs:assertion test="$value >= 0"/> <xs:assertion test="$value <= 100"/> </xs:restriction> </xs:simpleType>""") self.assertTrue(schema.types['Percentage'].is_valid('10')) self.assertTrue(schema.types['Percentage'].is_valid('100')) self.assertTrue(schema.types['Percentage'].is_valid('0')) self.assertFalse(schema.types['Percentage'].is_valid('-1')) self.assertFalse(schema.types['Percentage'].is_valid('101')) self.assertFalse(schema.types['Percentage'].is_valid('90.1')) if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD simple types with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tests/validators/test_wildcards.py�������������������������������������������������0000664�0000000�0000000�00000102777�14211403446�0022466�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest from xmlschema import XMLSchemaParseError from xmlschema.validators import XMLSchema11, XsdDefaultOpenContent from xmlschema.testing import XsdValidatorTestCase class TestXsdWildcards(XsdValidatorTestCase): def test_parsing(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:choice> <xs:any namespace=" ##any "/> <xs:any namespace="##local"/> <xs:any namespace="##other"/> <xs:any namespace="##targetNamespace foo bar"/> <xs:any namespace="##local foo bar"/> <xs:any namespace="##targetNamespace ##local foo bar"/> </xs:choice> </xs:group> </xs:schema>""") self.assertEqual(schema.groups['group1'][0].namespace, ('##any',)) self.assertEqual(schema.groups['group1'][1].namespace, ['']) self.assertEqual(schema.groups['group1'][2].namespace, ['##other']) self.assertEqual(schema.groups['group1'][3].namespace, ['tns1', 'foo', 'bar']) self.assertEqual(schema.groups['group1'][4].namespace, ['', 'foo', 'bar']) self.assertEqual(schema.groups['group1'][5].namespace, ['tns1', '', 'foo', 'bar']) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:choice> <xs:any namespace="##all"/> <xs:any processContents="any"/> </xs:choice> </xs:group> </xs:schema>""", validation='lax') errors = schema.all_errors self.assertIn("wrong value '##all' in 'namespace' attribute", str(errors[1])) self.assertIn("value must be one of ['skip'", str(errors[0])) def test_overlap(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:choice> <xs:any namespace="##local"/> <xs:any namespace="##other"/> <xs:any namespace="##targetNamespace foo bar"/> </xs:choice> </xs:group> </xs:schema>""") any1, any2, any3 = schema.groups['group1'][:] self.assertFalse(any1.is_overlap(any2)) self.assertFalse(any2.is_overlap(any1)) self.assertTrue(any3.is_matching('{foo}x')) self.assertTrue(any3.is_matching('{bar}x')) self.assertTrue(any3.is_matching('{tns1}x')) def test_any_wildcard(self): schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##other" processContents="skip"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].namespace, ['##other']) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##targetNamespace" processContents="skip"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].namespace, ['']) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="ns ##targetNamespace" processContents="skip"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].namespace, ['ns', '']) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="tns2 tns1 tns3" processContents="skip"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].namespace, ['tns2', 'tns1', 'tns3']) self.assertEqual(schema.types['taggedType'].content[-1].min_occurs, 1) self.assertEqual(schema.types['taggedType'].content[-1].max_occurs, 1) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any minOccurs="10" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].namespace, ('##any',)) self.assertEqual(schema.types['taggedType'].content[-1].min_occurs, 10) self.assertIsNone(schema.types['taggedType'].content[-1].max_occurs) def test_any_attribute_wildcard(self): schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##other" processContents="skip"/> </xs:sequence> <xs:anyAttribute namespace="tns1:foo"/> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].attributes[None].namespace, ['tns1:foo']) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##other" processContents="skip"/> </xs:sequence> <xs:anyAttribute namespace="##targetNamespace"/> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].attributes[None].namespace, ['']) def test_namespace_variants(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:sequence> <xs:any namespace="urn:a" processContents="skip"/> <xs:any namespace="" processContents="lax"/> </xs:sequence> </xs:group> </xs:schema>""") any1 = schema.groups['group1'][0] self.assertEqual(any1.namespace, ['urn:a']) any2 = schema.groups['group1'][1] self.assertEqual(any2.namespace, []) class TestXsd11Wildcards(TestXsdWildcards): schema_class = XMLSchema11 def test_parsing(self): super(TestXsd11Wildcards, self).test_parsing() schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:choice> <xs:any notNamespace="##all"/> </xs:choice> </xs:group> </xs:schema>""", validation='lax') errors = schema.all_errors self.assertIn("wrong value '##all' in 'notNamespace' attribute", str(errors[0])) def test_is_restriction(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns1="tns1" targetNamespace="tns1"> <xs:group name="group1"> <xs:sequence> <!-- Case #1 --> <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1 tns2"/> <xs:any notNamespace="tns1 tns2 tns3"/> <!-- Case #2 --> <xs:any namespace="##any"/> <xs:any namespace="##local" notQName="a b"/> <xs:any namespace="##local" notQName="##defined a b"/> <!-- Case #3 --> <xs:any namespace="##any" notQName="a b c d"/> <xs:any namespace="##local" notQName="a b e"/> <xs:any notNamespace="##local" notQName="tns1:c d e"/> </xs:sequence> </xs:group> </xs:schema>""") any1, any2, any3 = schema.groups['group1'][:3] self.assertEqual(repr(any1), "Xsd11AnyElement(not_namespace=['tns1'], " "process_contents='strict', occurs=[1, 1])") self.assertEqual(repr(any2), "Xsd11AnyElement(not_namespace=['tns1', 'tns2'], " "process_contents='strict', occurs=[1, 1])") self.assertTrue(any1.is_restriction(any1)) self.assertFalse(any1.is_restriction(any2)) self.assertFalse(any1.is_restriction(any3)) self.assertTrue(any2.is_restriction(any1)) self.assertTrue(any2.is_restriction(any2)) self.assertFalse(any2.is_restriction(any3)) self.assertTrue(any3.is_restriction(any1)) self.assertTrue(any3.is_restriction(any2)) self.assertTrue(any3.is_restriction(any3)) any1, any2, any3 = schema.groups['group1'][3:6] self.assertEqual(repr(any1), "Xsd11AnyElement(namespace=('##any',), " "process_contents='strict', occurs=[1, 1])") self.assertEqual(repr(any2), "Xsd11AnyElement(namespace=[''], " "process_contents='strict', occurs=[1, 1])") self.assertTrue(any1.is_restriction(any1)) self.assertTrue(any2.is_restriction(any1)) self.assertTrue(any3.is_restriction(any1)) any1, any2, any3 = schema.groups['group1'][6:9] self.assertFalse(any2.is_restriction(any1)) self.assertTrue(any3.is_restriction(any1)) def test_wildcard_union(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:sequence> <xs:any namespace="tns1"/> <xs:any namespace="tns1 tns2"/> <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1 tns2"/> <xs:any namespace="##any"/> <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> <xs:any namespace="##other"/> <xs:any notNamespace="##local tns1"/> <xs:any namespace="##other"/> <xs:any notNamespace="tns2"/> </xs:sequence> </xs:group> </xs:schema>""") # <xs:any namespace="tns1"/> <xs:any namespace="tns1 tns2"/> any1, any2 = schema.groups['group1'][:2] self.assertListEqual(any1.namespace, ['tns1']) any1.union(any2) self.assertListEqual(any1.namespace, ['tns1', 'tns2']) # <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1 tns2"/> any1, any2 = schema.groups['group1'][2:4] self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1']) any1.union(any2) self.assertListEqual(any1.not_namespace, ['tns1']) any2.union(any1) self.assertListEqual(any2.not_namespace, ['tns1']) # <xs:any namespace="##any"/> <xs:any notNamespace="tns1"/> any1, any2 = schema.groups['group1'][4:6] any1.union(any2) self.assertEqual(any1.namespace, ('##any',)) self.assertEqual(any1.not_namespace, ()) # <xs:any namespace="##other"/> <xs:any notNamespace="tns1"/> any1, any2 = schema.groups['group1'][6:8] any1.union(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1']) # <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> any1, any2 = schema.groups['group1'][8:10] any1.union(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1']) # <xs:any namespace="##other"/> <xs:any notNamespace="##local tns1"/> any1, any2 = schema.groups['group1'][10:12] any1.union(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['', 'tns1']) # <xs:any namespace="##other"/> <xs:any notNamespace="tns2"/> any1, any2 = schema.groups['group1'][12:14] any1.union(any2) self.assertListEqual(any1.namespace, ['##any']) self.assertListEqual(any1.not_namespace, []) def test_wildcard_intersection(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="tns1"> <xs:group name="group1"> <xs:sequence> <xs:any namespace="tns1"/> <xs:any namespace="tns1 tns2"/> <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1 tns2"/> <xs:any namespace="##any"/> <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> <xs:any namespace="##other"/> <xs:any notNamespace="##local tns1"/> <xs:any namespace="##other"/> <xs:any notNamespace="tns2"/> <xs:any namespace="##any" notQName="##defined qn1"/> <xs:any namespace="##local" notQName="##defined"/> </xs:sequence> </xs:group> </xs:schema>""") # <xs:any namespace="tns1"/> <xs:any namespace="tns1 tns2"/> any1, any2 = schema.groups['group1'][:2] self.assertListEqual(any1.namespace, ['tns1']) any1.intersection(any2) self.assertListEqual(any1.namespace, ['tns1']) # <xs:any notNamespace="tns1"/> <xs:any notNamespace="tns1 tns2"/> any1, any2 = schema.groups['group1'][2:4] self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1']) any1.intersection(any2) self.assertListEqual(any1.not_namespace, ['tns1', 'tns2']) any2.intersection(any1) self.assertListEqual(any2.not_namespace, ['tns1', 'tns2']) # <xs:any namespace="##any"/> <xs:any notNamespace="tns1"/> any1, any2 = schema.groups['group1'][4:6] any1.intersection(any2) self.assertEqual(any1.namespace, []) self.assertEqual(any1.not_namespace, ['tns1']) # <xs:any namespace="##other"/> <xs:any notNamespace="tns1"/> any1, any2 = schema.groups['group1'][6:8] any1.intersection(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1', '']) # <xs:any notNamespace="tns1"/> <xs:any namespace="##other"/> any1, any2 = schema.groups['group1'][8:10] any1.intersection(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns1', '']) # <xs:any namespace="##other"/> <xs:any notNamespace="##local tns1"/> any1, any2 = schema.groups['group1'][10:12] any1.intersection(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['', 'tns1']) # <xs:any namespace="##other"/> <xs:any notNamespace="tns2"/> any1, any2 = schema.groups['group1'][12:14] any1.intersection(any2) self.assertListEqual(any1.namespace, []) self.assertListEqual(any1.not_namespace, ['tns2', 'tns1', '']) # <xs:any namespace="##any" notQName="##defined qn1"/> # <xs:any namespace="##local" notQName="##defined"/> any1, any2 = schema.groups['group1'][14:16] any1.intersection(any2) self.assertListEqual(any1.namespace, ['']) self.assertListEqual(any1.not_qname, ['##defined', 'qn1']) def test_open_content_mode_interleave(self): schema = self.check_schema(""" <xs:element name="Book"> <xs:complexType> <xs:openContent mode="interleave"> <xs:any /> </xs:openContent> <xs:sequence> <xs:element name="Title" type="xs:string"/> <xs:element name="Author" type="xs:string" /> <xs:element name="Date" type="xs:gYear"/> <xs:element name="ISBN" type="xs:string"/> <xs:element name="Publisher" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>""") self.assertEqual(schema.elements['Book'].type.open_content.mode, 'interleave') self.assertEqual(schema.elements['Book'].type.open_content.any_element.min_occurs, 0) self.assertIsNone(schema.elements['Book'].type.open_content.any_element.max_occurs) schema = self.check_schema(""" <xs:complexType name="name"> <xs:openContent> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['name'].open_content.mode, 'interleave') self.check_schema(""" <xs:complexType name="name"> <xs:openContent /> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) def test_open_content_mode_suffix(self): schema = self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="suffix"> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['name'].open_content.mode, 'suffix') self.assertEqual(schema.types['name'].open_content.any_element.min_occurs, 0) self.assertIsNone(schema.types['name'].open_content.any_element.max_occurs) self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="suffix"/> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) def test_open_content_mode_none(self): schema = self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="none"/> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['name'].open_content.mode, 'none') self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="none"> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) def test_open_content_allowed(self): self.check_schema(""" <xs:complexType name="choiceType"> <xs:openContent> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:choice> <xs:element name="a" type="xs:float"/> <xs:element name="b" type="xs:string"/> <xs:element name="c" type="xs:int"/> </xs:choice> </xs:complexType>""") def test_open_content_not_allowed(self): self.check_schema(""" <xs:complexType name="wrongType"> <xs:openContent> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:simpleContent> <xs:restriction base="xs:string" /> </xs:simpleContent> </xs:complexType>""", XMLSchemaParseError) self.check_schema(""" <xs:complexType name="wrongType"> <xs:openContent> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:complexContent> <xs:restriction base="xs:anyType" /> </xs:complexContent> </xs:complexType>""", XMLSchemaParseError) with self.assertRaises(XMLSchemaParseError): self.schema_class("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:openContent> <xs:any namespace="##other" processContents="skip"/> </xs:openContent> <xs:element name="root" /> </xs:schema>""") def test_open_content_wrong_attributes(self): self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="wrong"/> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="suffix"> <xs:any minOccurs="1" namespace="##other" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) self.check_schema(""" <xs:complexType name="name"> <xs:openContent mode="suffix"> <xs:any maxOccurs="1000" namespace="##other" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="given" type="xs:string"/> <xs:element name="middle" type="xs:string" minOccurs="0"/> <xs:element name="family" type="xs:string"/> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) def test_default_open_content(self): schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:defaultOpenContent> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> <xs:element name="root" /> </xs:schema>""") self.assertIsInstance(schema.default_open_content, XsdDefaultOpenContent) self.assertFalse(schema.default_open_content.applies_to_empty) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:defaultOpenContent appliesToEmpty="true"> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> <xs:element name="root" /> </xs:schema>""") self.assertTrue(schema.default_open_content.applies_to_empty) with self.assertRaises(XMLSchemaParseError): self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:defaultOpenContent appliesToEmpty="wrong"> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> <xs:element name="root" /> </xs:schema>""") with self.assertRaises(XMLSchemaParseError): self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" /> <xs:defaultOpenContent> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> </xs:schema>""") with self.assertRaises(XMLSchemaParseError): self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:defaultOpenContent> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> <xs:defaultOpenContent> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> <xs:element name="root" /> </xs:schema>""") with self.assertRaises(XMLSchemaParseError): self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" /> <xs:defaultOpenContent mode="wrong"> <xs:any namespace="##other" processContents="skip"/> </xs:defaultOpenContent> </xs:schema>""") with self.assertRaises(XMLSchemaParseError): self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" /> <xs:defaultOpenContent mode="none" /> </xs:schema>""") def test_open_content_restriction(self): schema = self.check_schema(""" <xs:complexType name="baseType"> <xs:openContent> <xs:any namespace="tns1 tns2" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="derivedType"> <xs:complexContent> <xs:restriction base="baseType"> <xs:openContent> <xs:any namespace="tns1" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType>""") self.assertEqual(schema.types['derivedType'].content[0].name, 'foo') self.check_schema(""" <xs:complexType name="baseType"> <xs:openContent> <xs:any namespace="tns1 tns2" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="derivedType"> <xs:complexContent> <xs:restriction base="baseType"> <xs:openContent> <xs:any namespace="##any" processContents="skip"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType>""", XMLSchemaParseError) def test_open_content_extension(self): schema = self.check_schema(""" <xs:complexType name="baseType"> <xs:openContent mode="suffix"> <xs:any namespace="tns1" processContents="lax"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="derivedType"> <xs:complexContent> <xs:extension base="baseType"> <xs:openContent> <xs:any namespace="tns1 tns2" processContents="lax"/> </xs:openContent> <xs:sequence> <xs:element name="bar" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>""") self.assertEqual(schema.types['derivedType'].content[0][0].name, 'foo') self.assertEqual(schema.types['derivedType'].content[1][0].name, 'bar') self.check_schema(""" <xs:complexType name="baseType"> <xs:openContent mode="interleave"> <xs:any namespace="tns1" processContents="lax"/> </xs:openContent> <xs:sequence> <xs:element name="foo" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="derivedType"> <xs:complexContent> <xs:extension base="baseType"> <xs:openContent> <!-- processContents="strict" is more restrictive --> <xs:any namespace="tns1 tns2" processContents="strict"/> </xs:openContent> <xs:sequence> <xs:element name="bar" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>""", XMLSchemaParseError) def test_not_qname_attribute(self): self.assertIsInstance(self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="tns1" targetNamespace="tns1"> <xs:complexType name="type1"> <xs:openContent> <xs:any notQName="ns:a" processContents="lax" /> </xs:openContent> </xs:complexType> </xs:schema>"""), XMLSchema11) self.assertIsInstance(self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="tns1" targetNamespace="tns1"> <xs:complexType name="type1"> <xs:sequence> <xs:any notQName="ns:a" processContents="lax" /> </xs:sequence> </xs:complexType> </xs:schema>"""), XMLSchema11) self.check_schema(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:group name="group1"> <xs:sequence> <xs:any notNamespace="##local" notQName="c d e"/> </xs:sequence> </xs:group> </xs:schema>""", XMLSchemaParseError) def test_any_wildcard(self): super(TestXsd11Wildcards, self).test_any_wildcard() self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##other" notNamespace="##targetNamespace" /> </xs:sequence> </xs:complexType>""", XMLSchemaParseError) schema = self.check_schema(""" <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any notNamespace="##targetNamespace" /> </xs:sequence> </xs:complexType>""") self.assertEqual(schema.types['taggedType'].content[-1].not_namespace, ['']) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns1="tns1" targetNamespace="tns1"> <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##targetNamespace" notQName="tns1:foo tns1:bar"/> </xs:sequence> </xs:complexType> </xs:schema>""") self.assertEqual(schema.types['taggedType'].content[-1].not_qname, ['{tns1}foo', '{tns1}bar']) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns1="tns1" targetNamespace="tns1"> <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##targetNamespace" notQName="##defined tns1:foo ##definedSibling"/> </xs:sequence> </xs:complexType> </xs:schema>""") self.assertEqual(schema.types['taggedType'].content[-1].not_qname, ['##defined', '{tns1}foo', '##definedSibling']) def test_any_attribute_wildcard(self): super(TestXsd11Wildcards, self).test_any_attribute_wildcard() schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns1="tns1" targetNamespace="tns1"> <xs:complexType name="taggedType"> <xs:sequence> <xs:element name="tag" type="xs:string"/> <xs:any namespace="##other" processContents="skip"/> </xs:sequence> <xs:anyAttribute notQName="tns1:foo"/> </xs:complexType> </xs:schema>""") self.assertEqual(schema.types['taggedType'].attributes[None].namespace, ('##any',)) self.assertEqual(schema.types['taggedType'].attributes[None].not_qname, ['{tns1}foo']) schema = self.schema_class(""" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="barType"> <xs:anyAttribute notNamespace="tns1"/> </xs:complexType> </xs:schema>""") self.assertEqual(schema.types['barType'].attributes[None].not_namespace, ['tns1']) self.assertEqual(repr(schema.types['barType'].attributes[None]), "Xsd11AnyAttribute(not_namespace=['tns1'], process_contents='strict')") if __name__ == '__main__': import platform header_template = "Test xmlschema's XSD wildcards with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �xmlschema-1.10.0/tests/validators/test_xsdbase.py���������������������������������������������������0000664�0000000�0000000�00000102347�14211403446�0022134�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env python # # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import unittest import os import platform import re from textwrap import dedent try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None from xmlschema.validators import XsdValidator, XsdComponent, XMLSchema10, XMLSchema11, \ XMLSchemaParseError, XMLSchemaValidationError, XsdAnnotation, XsdGroup, XsdSimpleType from xmlschema.names import XSD_NAMESPACE, XSD_ELEMENT, XSD_ANNOTATION, XSD_ANY_TYPE from xmlschema.etree import ElementTree from xmlschema.dataobjects import DataElement CASES_DIR = os.path.join(os.path.dirname(__file__), '../test_cases') class TestXsdValidator(unittest.TestCase): def test_initialization(self): validator = XsdValidator() self.assertEqual(validator.validation, 'strict') validator = XsdValidator(validation='lax') self.assertEqual(validator.validation, 'lax') self.assertListEqual(validator.errors, []) def test_string_representation(self): validator = XsdValidator() tmpl = '<xmlschema.validators.xsdbase.XsdValidator object at {}>' string_repr = str(validator) if platform.python_implementation() == 'PyPy' or platform.system() == 'Windows': string_repr = re.sub(r'0x[0]+', '0x', string_repr, 1) self.assertEqual(string_repr.lower(), tmpl.format(hex(id(validator))).lower()) def test_parse_error(self): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') schema = XMLSchema10(xsd_file) with self.assertRaises(TypeError): schema.parse_error("test error", elem=(1, 2)) with self.assertRaises(TypeError): schema.parse_error(b"test error") with self.assertRaises(XMLSchemaParseError): schema.parse_error("test error") self.assertEqual(len(schema.errors), 0) schema.parse_error("test error", validation='skip') self.assertEqual(len(schema.errors), 0) schema.parse_error("test error", validation='lax') self.assertEqual(len(schema.errors), 1) schema.parse_error(XMLSchemaParseError(schema, "test error"), validation='lax') self.assertEqual(len(schema.errors), 2) schema.parse_error(ValueError("wrong value"), validation='lax') self.assertEqual(len(schema.errors), 3) schema.parse_error(ValueError("'invalid value'"), validation='lax') self.assertEqual(len(schema.errors), 4) self.assertEqual(schema.errors[-1].message, "invalid value") def test_copy(self): validator = XsdValidator(validation='lax') validator.parse_error(ValueError("test error")) self.assertEqual(len(validator.errors), 1) self.assertListEqual(validator.copy().errors, validator.errors) def test_valid_schema(self): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') schema = XMLSchema10(xsd_file, build=False) self.assertEqual(schema.validity, 'notKnown') self.assertEqual(len(schema.all_errors), 0) schema.build() self.assertEqual(schema.validity, 'valid') self.assertEqual(len(schema.all_errors), 0) def test_invalid_schema(self): xsd_text = """<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" minOccurs="0"/> </xs:schema>""" with self.assertRaises(XMLSchemaParseError): XMLSchema10(xsd_text) schema = XMLSchema10(xsd_text, validation='lax') self.assertEqual(schema.validity, 'invalid') self.assertEqual(len(schema.all_errors), 2) # One by meta-schema check schema = XMLSchema10(xsd_text, validation='skip') self.assertEqual(schema.validity, 'notKnown') self.assertEqual(len(schema.all_errors), 0) def test_parse_xpath_default_namespace(self): xsd_text = """<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""" schema = XMLSchema11(xsd_text) elem = ElementTree.Element('A') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') elem = ElementTree.Element('A', xpathDefaultNamespace='##local') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') elem = ElementTree.Element('A', xpathDefaultNamespace='##defaultNamespace') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') elem = ElementTree.Element('A', xpathDefaultNamespace='##targetNamespace') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') xsd_text = """<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="tns0" targetNamespace="tns0"> <xs:element name="root"/> </xs:schema>""" schema = XMLSchema11(xsd_text, validation='lax') elem = ElementTree.Element('A') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') elem = ElementTree.Element('A', xpathDefaultNamespace='##local') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') elem = ElementTree.Element('A', xpathDefaultNamespace='##defaultNamespace') self.assertEqual(schema._parse_xpath_default_namespace(elem), 'tns0') elem = ElementTree.Element('A', xpathDefaultNamespace='##targetNamespace') self.assertEqual(schema._parse_xpath_default_namespace(elem), 'tns0') elem = ElementTree.Element('A', xpathDefaultNamespace='tns1') self.assertEqual(schema._parse_xpath_default_namespace(elem), 'tns1') elem = ElementTree.Element('A', xpathDefaultNamespace='tns0 tns1') self.assertEqual(schema._parse_xpath_default_namespace(elem), '') self.assertIn('tns0 tns1', schema.errors[-1].message) class TestXsdComponent(unittest.TestCase): class FakeElement(XsdComponent): @property def built(self): return super().built _ADMITTED_TAGS = (XSD_ELEMENT,) @classmethod def setUpClass(cls): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') cls.schema = XMLSchema10(xsd_file) def test_initialization(self): with self.assertRaises(AttributeError): XsdComponent(elem=None, schema=self.schema) with self.assertRaises(ValueError): XsdComponent(elem=ElementTree.Element('A'), schema=self.schema) def test_errors(self): schema = XMLSchema10(dedent("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" type="xs:string"> <xs:simpleType> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:element> </xs:schema>"""), validation='lax') xsd_element = schema.elements['root'] self.assertEqual(len(schema.all_errors), 1) self.assertEqual(len(xsd_element.errors), 1) xsd_element.elem.attrib.pop('type') xsd_element.elem = xsd_element.elem self.assertEqual(len(schema.all_errors), 0) self.assertEqual(len(xsd_element.errors), 0) def test_is_override(self): self.assertFalse(self.schema.elements['cars'].is_override()) self.assertFalse(self.schema.elements['cars'].type.content[0].is_override()) def test_representation(self): schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="node"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute ref="slot"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:attribute name="slot" type="xs:string"/> </xs:schema>""") self.assertEqual(repr(schema.elements['node']), "XsdElement(name='node', occurs=[1, 1])") self.assertEqual(repr(schema.attributes['slot']), "XsdAttribute(name='slot')") self.assertEqual(repr(schema.elements['node'].type.attributes['slot']), "XsdAttribute(ref='slot')") def test_parse_reference(self): group = self.schema.elements['vehicles'].type.content name = '{%s}motorbikes' % XSD_NAMESPACE elem = ElementTree.Element(XSD_ELEMENT, name=name) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) self.assertIsNone(xsd_element._parse_reference()) elem = ElementTree.Element(XSD_ELEMENT, name=name, ref=name) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() elem = ElementTree.Element(XSD_ELEMENT, ref=name) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) xsd_element._parse_reference() elem = ElementTree.Element(XSD_ELEMENT, ref='tns0:motorbikes') xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() elem = ElementTree.Element(XSD_ELEMENT, ref=name) elem.append(ElementTree.Element('child')) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() elem = ElementTree.Element(XSD_ELEMENT) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_reference() def test_parse_child_component(self): name = '{%s}motorbikes' % self.schema.target_namespace elem = ElementTree.Element(XSD_ELEMENT, name=name) elem.append(ElementTree.Element(XSD_ANNOTATION)) elem.append(ElementTree.Element('child1')) elem.append(ElementTree.Element('child2')) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) self.assertEqual(xsd_element._parse_child_component(elem, strict=False), elem[1]) with self.assertRaises(XMLSchemaParseError): xsd_element._parse_child_component(elem) self.assertEqual(len(xsd_element.errors), 0) xsd_element.validation = 'lax' xsd_element._parse_child_component(elem) self.assertEqual(len(xsd_element.errors), 1) def test_parse_target_namespace(self): name = '{%s}motorbikes' % self.schema.target_namespace elem = ElementTree.Element(XSD_ELEMENT, name=name, targetNamespace='tns0') group = self.schema.elements['vehicles'].type.content xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_target_namespace() self.assertIn("must have the same namespace", ctx.exception.message) xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) self.assertIsNone(xsd_element._parse_target_namespace()) self.assertEqual(xsd_element.name, '{tns0}motorbikes') elem = ElementTree.Element(XSD_ELEMENT, targetNamespace='tns0') xsd_element = self.FakeElement(elem=elem, name=None, schema=self.schema, parent=group) with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_target_namespace() self.assertIn("attribute 'name' must be present", ctx.exception.message) elem = ElementTree.Element(XSD_ELEMENT, name=name, form='qualified', targetNamespace='tns0') xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=group) with self.assertRaises(XMLSchemaParseError) as ctx: xsd_element._parse_target_namespace() self.assertIn("attribute 'form' must be absent", ctx.exception.message) elem = ElementTree.Element( XSD_ELEMENT, name='motobikes', targetNamespace=self.schema.target_namespace ) xsd_element = self.FakeElement(elem, self.schema, parent=group, name=name) self.assertIsNone(xsd_element._parse_target_namespace()) self.assertEqual(xsd_element.name, name) xsd_attribute = self.schema.types['vehicleType'].attributes['model'] xsd_attribute.elem.attrib['targetNamespace'] = 'tns0' with self.assertRaises(XMLSchemaParseError) as ctx: xsd_attribute._parse_target_namespace() self.assertIn("a declaration contained in a global complexType must " "have the same namespace", ctx.exception.message) del xsd_attribute.elem.attrib['targetNamespace'] with self.assertRaises(XMLSchemaParseError) as ctx: XMLSchema11("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root" targetNamespace=""/> </xs:schema>""") self.assertIn("use of attribute 'targetNamespace' is prohibited", ctx.exception.message) schema = XMLSchema11("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:complexType name="type0"> <xs:sequence> <xs:any namespace="http://xmlschema.test/ns"/> </xs:sequence> </xs:complexType> <xs:complexType name="type1"> <xs:complexContent> <xs:restriction base="type0"> <xs:sequence> <xs:element name="elem1" targetNamespace="http://xmlschema.test/ns" type="xs:integer"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="root" type="type1"/> </xs:schema>""") self.assertEqual(schema.elements['root'].type.content[0].target_namespace, 'http://xmlschema.test/ns') schema = XMLSchema11("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:complexType> <xs:sequence> <xs:element name="node" targetNamespace=""/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>""") self.assertEqual(schema.elements['root'].type.content[0].name, 'node') def test_id_property(self): name = '{%s}motorbikes' % self.schema.target_namespace elem = ElementTree.Element(XSD_ELEMENT, name=name, id='1999') xsd_element = self.FakeElement(elem=elem, name=name, schema=self.schema, parent=None) self.assertEqual(xsd_element.id, '1999') def test_validation_attempted(self): schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:notation name="content" public="text/html"/> <xs:element name="root"/> </xs:schema>""") self.assertEqual(schema.notations['content'].validation_attempted, 'full') def test_name_matching(self): name = '{%s}motorbikes' % self.schema.target_namespace elem = ElementTree.Element(XSD_ELEMENT, name=name) xsd_element = self.FakeElement(elem, self.schema, parent=None, name=name) self.assertFalse(xsd_element.is_matching('motorbikes')) self.assertFalse(xsd_element.is_matching('')) self.assertTrue( xsd_element.is_matching('motorbikes', default_namespace=self.schema.target_namespace) ) self.assertFalse(xsd_element.is_matching('{%s}bikes' % self.schema.target_namespace)) self.assertTrue(xsd_element.is_matching(name)) self.assertIs(xsd_element.match(name), xsd_element) def test_get_matching_item(self): xsd_element = self.schema.elements['vehicles'] self.assertIsNone(xsd_element.get_matching_item({})) self.assertTrue(xsd_element.get_matching_item({xsd_element.qualified_name: True})) self.assertTrue(xsd_element.get_matching_item({xsd_element.prefixed_name: True})) mapping = {xsd_element.local_name: True} self.assertIsNone(xsd_element.get_matching_item(mapping)) self.assertTrue(xsd_element.get_matching_item(mapping, match_local_name=True)) mapping = {xsd_element.type.local_name: True} # type.name is None self.assertIsNone(xsd_element.type.get_matching_item(mapping, match_local_name=True)) mapping = {'vhs:vehicles': True} self.assertIsNone(xsd_element.get_matching_item(mapping)) self.schema.namespaces['vhs'] = self.schema.target_namespace try: self.assertTrue(xsd_element.get_matching_item(mapping)) finally: self.schema.namespaces.pop('vhs') mapping = {'vhs:vehicles': {'xmlns:vhs': self.schema.target_namespace}} self.assertIs(xsd_element.get_matching_item(mapping), mapping['vhs:vehicles']) mapping = {'vhs:vehicles': {'xmlns:vhs': 'http://xmlschema.test/ns'}} self.assertIsNone(xsd_element.get_matching_item(mapping)) schema = XMLSchema10(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"/> </xs:schema>""")) xsd_element = schema.elements['root'] self.assertTrue(xsd_element.get_matching_item({'root': True})) self.assertIsNone(xsd_element.get_matching_item({'rook': True})) def test_get_global(self): xsd_element = self.schema.elements['vehicles'] self.assertIs(xsd_element.get_global(), xsd_element) xsd_type = self.schema.types['vehicleType'] self.assertIs(xsd_type.attributes['model'].get_global(), xsd_type) def test_get_parent_type(self): xsd_type = self.schema.types['vehicleType'] self.assertIs(xsd_type.attributes['model'].get_parent_type(), xsd_type) self.assertIsNone(xsd_type.get_parent_type()) def test_iter_components(self): name = '{%s}motorbikes' % self.schema.target_namespace elem = ElementTree.Element(XSD_ELEMENT, name=name) xsd_element = self.FakeElement(elem, self.schema, parent=None, name=name) self.assertListEqual(list(xsd_element.iter_components()), [xsd_element]) self.assertListEqual(list(xsd_element.iter_components(str)), []) def test_iter_ancestors(self): xsd_element = self.schema.elements['cars'].type.content[0] ancestors = [e for e in xsd_element.iter_ancestors()] self.assertListEqual(ancestors, [ self.schema.elements['cars'].type.content, self.schema.elements['cars'].type, self.schema.elements['cars'], ]) self.assertListEqual(list(xsd_element.iter_ancestors(str)), []) def test_tostring(self): cars_dump = str(self.schema.elements['cars'].tostring()) self.assertEqual(len(cars_dump.split('\n')), 7) self.assertIn('name="car" type="vh:vehicleType"', cars_dump) self.assertIsInstance(ElementTree.XML(cars_dump), ElementTree.Element) def test_annotations(self): schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:annotation/> </xs:element> </xs:schema>""") self.assertTrue(schema.elements['root'].annotation.built) schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:simpleType> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:element> </xs:schema>""") self.assertIsNone(schema.elements['root'].annotation) if lxml_etree is not None: root = lxml_etree.XML("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <!-- comment --> <xs:annotation/> </xs:element> </xs:schema>""") schema = XMLSchema10(root) self.assertTrue(schema.elements['root'].annotation.built) schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:annotation> <xs:appinfo/> <xs:documentation/> </xs:annotation> </xs:element> </xs:schema>""") self.assertEqual(len(schema.all_errors), 0) # XSD annotation errors found with meta-schema validation schema = XMLSchema10("""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="root"> <xs:annotation> <xs:documentation wrong="abc" source=""/> <xs:appinfo wrong="10" source=""/> <xs:element name="wrong"/> </xs:annotation> </xs:element> </xs:schema>""", validation='lax') self.assertEqual(len(schema.all_errors), 3) # Lazy XSD annotation build (errors not counted in schema.all_errors) xsd_element = schema.elements['root'] self.assertNotIn('_annotation', xsd_element.__dict__) annotation = xsd_element.annotation self.assertIsInstance(annotation, XsdAnnotation) self.assertIn('_annotation', xsd_element.__dict__) self.assertEqual(len(schema.all_errors), 3) self.assertEqual(len(annotation.errors), 0) # see issue 287 self.assertIsNone(annotation.annotation) class TestXsdType(unittest.TestCase): @classmethod def setUpClass(cls): cls.schema = XMLSchema10(dedent("""\ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:simpleType name="emptyType"> <xs:restriction base="xs:string"> <xs:length value="0"/> </xs:restriction> </xs:simpleType> <xs:complexType name="emptyType2"> <xs:attribute name="foo" type="xs:string"/> </xs:complexType> <xs:simpleType name="idType"> <xs:restriction base="xs:ID"/> </xs:simpleType> <xs:simpleType name="decimalType"> <xs:restriction base="xs:decimal"/> </xs:simpleType> <xs:simpleType name="dateTimeType"> <xs:restriction base="xs:dateTime"/> </xs:simpleType> <xs:simpleType name="fooType"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="fooListType"> <xs:list itemType="xs:string"/> </xs:simpleType> <xs:simpleType name="fooUnionType"> <xs:union memberTypes="xs:string xs:anyURI"/> </xs:simpleType> <xs:complexType name="barType"> <xs:sequence> <xs:element name="node"/> </xs:sequence> </xs:complexType> <xs:complexType name="barExtType"> <xs:complexContent> <xs:extension base="barType"> <xs:sequence> <xs:element name="node"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="barResType"> <xs:complexContent> <xs:restriction base="barType"> <xs:sequence> <xs:element name="node"/> </xs:sequence> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="mixedType" mixed="true"> <xs:sequence> <xs:element name="node" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="fooElem" type="fooType"/> <xs:element name="barElem" type="barType" block="extension"/> </xs:schema>""")) def test_content_type_label(self): self.assertEqual(self.schema.types['emptyType'].content_type_label, 'empty') self.assertEqual(self.schema.types['emptyType2'].content_type_label, 'empty') self.assertEqual(self.schema.types['fooType'].content_type_label, 'simple') self.assertEqual(self.schema.types['barType'].content_type_label, 'element-only') self.assertEqual(self.schema.types['mixedType'].content_type_label, 'mixed') def test_simple_type_property(self): self.assertIsInstance(self.schema.types['emptyType'].simple_type, XsdSimpleType) self.assertIsNone(self.schema.types['emptyType2'].simple_type) def test_model_group_property(self): self.assertIsNone(self.schema.types['emptyType'].model_group) self.assertIsInstance(self.schema.types['emptyType2'].model_group, XsdGroup) def test_root_type(self): self.assertIs(self.schema.types['fooType'].root_type, self.schema.meta_schema.types['string']) self.assertIs(self.schema.types['fooListType'].root_type, self.schema.meta_schema.types['string']) self.assertIs(self.schema.types['mixedType'].root_type, self.schema.maps.types[XSD_ANY_TYPE]) self.assertIs(self.schema.types['barExtType'].root_type, self.schema.maps.types[XSD_ANY_TYPE]) # xs:anyType used by the schema is equivalent but is not the same object of # the meta schema because it can be used as base for schema's complex types self.assertIs(self.schema.types['emptyType2'].root_type, self.schema.maps.types[XSD_ANY_TYPE]) def test_is_atomic(self): self.assertFalse(self.schema.types['barType'].is_atomic()) def test_is_list(self): self.assertFalse(self.schema.types['barType'].is_list()) self.assertTrue(self.schema.types['fooListType'].is_list()) self.assertFalse(self.schema.types['fooUnionType'].is_list()) def test_is_union(self): self.assertFalse(self.schema.types['barType'].is_union()) self.assertFalse(self.schema.types['fooListType'].is_union()) self.assertTrue(self.schema.types['fooUnionType'].is_union()) def test_is_datetime(self): self.assertFalse(self.schema.types['barType'].is_datetime()) self.assertTrue(self.schema.types['dateTimeType'].is_datetime()) def test_is_decimal(self): self.assertFalse(self.schema.types['barType'].is_decimal()) self.assertTrue(self.schema.types['decimalType'].is_decimal()) def test_is_dynamic_consistent(self): self.assertFalse(self.schema.types['fooType'].is_dynamic_consistent( self.schema.types['fooListType'] )) self.assertTrue(self.schema.types['fooType'].is_dynamic_consistent( self.schema.types['fooType'] )) def test_is_key(self): self.assertFalse(self.schema.types['fooType'].is_key()) self.assertTrue(self.schema.types['idType'].is_key()) def test_is_extension(self): self.assertFalse(self.schema.types['fooType'].is_extension()) self.assertTrue(self.schema.types['barExtType'].is_extension()) def test_is_restriction(self): self.assertTrue(self.schema.types['fooType'].is_restriction()) self.assertFalse(self.schema.types['barExtType'].is_restriction()) def test_is_blocked(self): element = self.schema.elements['fooElem'] self.assertFalse(self.schema.types['fooType'].is_blocked(element)) self.assertFalse(self.schema.types['barExtType'].is_blocked(element)) self.assertFalse(self.schema.types['barResType'].is_blocked(element)) element = self.schema.elements['barElem'] self.assertFalse(self.schema.types['fooType'].is_blocked(element)) self.assertTrue(self.schema.types['barExtType'].is_blocked(element)) self.assertFalse(self.schema.types['barResType'].is_blocked(element)) class TestValidationMixin(unittest.TestCase): @classmethod def setUpClass(cls): xsd_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xsd') cls.schema = XMLSchema10(xsd_file) def test_validate(self): xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xml') root = ElementTree.parse(xml_file).getroot() self.assertIsNone(self.schema.elements['vehicles'].validate(root)) xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles-1_error.xml') root = ElementTree.parse(xml_file).getroot() with self.assertRaises(XMLSchemaValidationError): self.schema.elements['vehicles'].validate(root) def test_decode(self): xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xml') root = ElementTree.parse(xml_file).getroot() obj = self.schema.elements['vehicles'].decode(root) self.assertIsInstance(obj, dict) self.assertIn(self.schema.elements['cars'].name, obj) self.assertIn(self.schema.elements['bikes'].name, obj) xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles-2_errors.xml') root = ElementTree.parse(xml_file).getroot() obj, errors = self.schema.elements['vehicles'].decode(root, validation='lax') self.assertIsInstance(obj, dict) self.assertIn(self.schema.elements['cars'].name, obj) self.assertIn(self.schema.elements['bikes'].name, obj) self.assertEqual(len(errors), 2) def test_decode_to_objects(self): xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xml') root = ElementTree.parse(xml_file).getroot() obj = self.schema.elements['vehicles'].to_objects(root) self.assertIsInstance(obj, DataElement) self.assertEqual(self.schema.elements['vehicles'].name, obj.tag) self.assertIs(obj.__class__, DataElement) obj = self.schema.elements['vehicles'].to_objects(root, with_bindings=True) self.assertIsInstance(obj, DataElement) self.assertEqual(self.schema.elements['vehicles'].name, obj.tag) self.assertIsNot(obj.__class__, DataElement) self.assertTrue(issubclass(obj.__class__, DataElement)) self.assertEqual(obj.__class__.__name__, 'VehiclesBinding') def test_encode(self): xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles.xml') obj = self.schema.decode(xml_file) root = self.schema.elements['vehicles'].encode(obj) self.assertEqual(root.tag, self.schema.elements['vehicles'].name) xml_file = os.path.join(CASES_DIR, 'examples/vehicles/vehicles-2_errors.xml') obj, errors = self.schema.decode(xml_file, validation='lax') root, errors2 = self.schema.elements['vehicles'].encode(obj, validation='lax') self.assertEqual(root.tag, self.schema.elements['vehicles'].name) def test_validation_error(self): elem = ElementTree.XML('<foo/>') with self.assertRaises(XMLSchemaValidationError): self.schema.validation_error('strict', 'Test error', obj=elem) self.assertIsInstance(self.schema.validation_error('lax', 'Test error'), XMLSchemaValidationError) self.assertIsInstance(self.schema.validation_error('lax', 'Test error'), XMLSchemaValidationError) self.assertIsInstance(self.schema.validation_error('skip', 'Test error'), XMLSchemaValidationError) error = self.schema.validation_error('lax', 'Test error') self.assertIsNone(error.obj) self.assertEqual(self.schema.validation_error('lax', error, obj=10).obj, 10) if __name__ == '__main__': header_template = "Test xmlschema's XSD base classes with Python {} on {}" header = header_template.format(platform.python_version(), platform.platform()) print('{0}\n{1}\n{0}'.format("*" * len(header), header)) unittest.main() �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/tox.ini����������������������������������������������������������������������������0000664�0000000�0000000�00000003630�14211403446�0015066�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������[tox] envlist = py{37,38,39,310}, pypy3, ep{250}, docs, flake8, mypy-py{37,38,39,310}, coverage, pytest skip_missing_interpreters = true toxworkdir = {homedir}/.tox/xmlschema [testenv] deps = elementpath>=2.5.0, <3.0.0 lxml jinja2 py{39,310}: memory_profiler docs: Sphinx docs: sphinx_rtd_theme flake8: flake8 coverage: coverage commands = python -m unittest tests/test_etree_import.py -k before python -m unittest tests/test_etree_import.py -k after python -m unittest tests/test_etree_import.py -k inconsistent python -m unittest whitelist_externals = make [testenv:pypy3] commands = python -m unittest [testenv:ep250] deps = elementpath==2.5.0 lxml [testenv:docs] commands = make -C doc html make -C doc latexpdf make -C doc doctest [flake8] max-line-length = 100 [testenv:flake8] commands = flake8 xmlschema [testenv:mypy-py37] deps = mypy==0.931 elementpath==2.5.0 lxml-stubs jinja2 commands = mypy --config-file {toxinidir}/mypy.ini xmlschema [testenv:mypy-py{38,39,310}] deps = mypy==0.931 elementpath==2.5.0 lxml-stubs jinja2 commands = mypy --config-file {toxinidir}/mypy.ini xmlschema python tests/test_typing.py [testenv:coverage] commands = coverage erase coverage run -a -m unittest tests/test_etree_import.py -k before coverage run -a -m unittest tests/test_etree_import.py -k after coverage run -a -m unittest tests/test_etree_import.py -k inconsistent coverage run -a -m unittest coverage report -m [testenv:pytest] deps = pytest pytest-randomly elementpath>=2.5.0, <3.0.0 lxml jinja2 mypy==0.931 lxml-stubs commands = pytest tests -ra [testenv:build] deps = setuptools wheel commands = python setup.py clean --all python setup.py sdist --dist-dir {toxinidir}/dist python setup.py bdist_wheel --dist-dir {toxinidir}/dist ��������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/�������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0015532�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/__init__.py��������������������������������������������������������������0000664�0000000�0000000�00000005370�14211403446�0017650�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# -*- coding: utf-8 -*- # # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from . import limits from .exceptions import XMLSchemaException, XMLResourceError, XMLSchemaNamespaceError from .etree import ElementData, etree_tostring from .resources import normalize_url, normalize_locations, fetch_resource, \ fetch_namespaces, fetch_schema_locations, fetch_schema, XMLResource from .xpath import ElementPathMixin from .converters import XMLSchemaConverter, \ UnorderedConverter, ParkerConverter, BadgerFishConverter, \ AbderaConverter, JsonMLConverter, ColumnarConverter from .dataobjects import DataElement, DataElementConverter, DataBindingConverter from .documents import validate, is_valid, iter_errors, iter_decode, \ to_dict, to_json, from_json, XmlDocument from .validators import ( XMLSchemaValidatorError, XMLSchemaParseError, XMLSchemaNotBuiltError, XMLSchemaModelError, XMLSchemaModelDepthError, XMLSchemaValidationError, XMLSchemaDecodeError, XMLSchemaEncodeError, XMLSchemaChildrenValidationError, XMLSchemaIncludeWarning, XMLSchemaImportWarning, XMLSchemaTypeTableWarning, XsdGlobals, XMLSchemaBase, XMLSchema, XMLSchema10, XMLSchema11, XsdComponent, XsdType, XsdElement, XsdAttribute ) __version__ = '1.10.0' __author__ = "Davide Brunato" __contact__ = "brunato@sissa.it" __copyright__ = "Copyright 2016-2022, SISSA" __license__ = "MIT" __status__ = "Production/Stable" __all__ = [ 'limits', 'XMLSchemaException', 'XMLResourceError', 'XMLSchemaNamespaceError', 'etree_tostring', 'normalize_url', 'normalize_locations', 'fetch_resource', 'fetch_namespaces', 'fetch_schema_locations', 'fetch_schema', 'XMLResource', 'ElementPathMixin', 'ElementData', 'XMLSchemaConverter', 'UnorderedConverter', 'ParkerConverter', 'BadgerFishConverter', 'AbderaConverter', 'JsonMLConverter', 'ColumnarConverter', 'DataElement', 'DataElementConverter', 'DataBindingConverter', 'validate', 'is_valid', 'iter_errors', 'iter_decode', 'to_dict', 'to_json', 'from_json', 'XmlDocument', 'XMLSchemaValidatorError', 'XMLSchemaParseError', 'XMLSchemaNotBuiltError', 'XMLSchemaModelError', 'XMLSchemaModelDepthError', 'XMLSchemaValidationError', 'XMLSchemaDecodeError', 'XMLSchemaEncodeError', 'XMLSchemaChildrenValidationError', 'XMLSchemaIncludeWarning', 'XMLSchemaImportWarning', 'XMLSchemaTypeTableWarning', 'XsdGlobals', 'XMLSchemaBase', 'XMLSchema', 'XMLSchema10', 'XMLSchema11', 'XsdComponent', 'XsdType', 'XsdElement', 'XsdAttribute', ] ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/aliases.py���������������������������������������������������������������0000664�0000000�0000000�00000011757�14211403446�0017540�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ Type aliases for static typing analysis. In a type checking context the aliases are defined from effective classes imported from package modules. In a runtime context the aliases cannot be set from the same bases, due to circular imports, so they are set with a common dummy subscriptable type to keep compatibility. """ from typing import TYPE_CHECKING, Optional, TypeVar __all__ = ['ElementType', 'ElementTreeType', 'XMLSourceType', 'NamespacesType', 'NormalizedLocationsType', 'LocationsType', 'NsmapType', 'ParentMapType', 'LazyType', 'SchemaType', 'BaseXsdType', 'SchemaElementType', 'SchemaAttributeType', 'SchemaGlobalType', 'GlobalMapType', 'ModelGroupType', 'ModelParticleType', 'XPathElementType', 'AtomicValueType', 'NumericValueType', 'DateTimeType', 'SchemaSourceType', 'ConverterType', 'ComponentClassType', 'ExtraValidatorType', 'DecodeType', 'IterDecodeType', 'JsonDecodeType', 'EncodeType', 'IterEncodeType', 'DecodedValueType', 'EncodedValueType'] if TYPE_CHECKING: from pathlib import Path from decimal import Decimal from typing import Callable, Dict, List, IO, Iterator, MutableMapping, Tuple, Type, Union from elementpath.datatypes import NormalizedString, QName, Float10, Integer, \ Time, Base64Binary, HexBinary, AnyURI, Duration from elementpath.datatypes.datetime import OrderedDateTime from .etree import ElementTree from .resources import XMLResource from .converters import XMLSchemaConverter from .validators import XMLSchemaValidationError, XsdComponent, XMLSchemaBase, \ XsdComplexType, XsdSimpleType, XsdElement, XsdAnyElement, XsdAttribute, \ XsdAnyAttribute, XsdAssert, XsdGroup, XsdAttributeGroup, XsdNotation ## # Type aliases for ElementTree ElementType = ElementTree.Element ElementTreeType = ElementTree.ElementTree XMLSourceType = Union[str, bytes, Path, IO[str], IO[bytes], ElementType, ElementTreeType] NamespacesType = MutableMapping[str, str] ## # Type aliases for XML resources NormalizedLocationsType = List[Tuple[str, str]] LocationsType = Union[Tuple[Tuple[str, str], ...], Dict[str, str], NormalizedLocationsType] NsmapType = Union[List[Tuple[str, str]], MutableMapping[str, str]] ParentMapType = Dict[ElementType, Optional[ElementType]] LazyType = Union[bool, int] ## # Type aliases for XSD components SchemaSourceType = Union[str, bytes, Path, IO[str], IO[bytes], XMLResource, ElementTree.Element, ElementTree.ElementTree] SchemaType = XMLSchemaBase BaseXsdType = Union[XsdSimpleType, XsdComplexType] SchemaElementType = Union[XsdElement, XsdAnyElement] SchemaAttributeType = Union[XsdAttribute, XsdAnyAttribute] SchemaGlobalType = Union[XsdNotation, BaseXsdType, XsdElement, XsdAttribute, XsdAttributeGroup, XsdGroup] ModelGroupType = XsdGroup ModelParticleType = Union[XsdElement, XsdAnyElement, XsdGroup] ComponentClassType = Union[None, Type[XsdComponent], Tuple[Type[XsdComponent], ...]] XPathElementType = Union[XsdElement, XsdAnyElement, XsdAssert] C = TypeVar('C') GlobalMapType = Dict[str, Union[C, Tuple[ElementType, SchemaType]]] ## # Type aliases for datatypes AtomicValueType = Union[str, int, float, Decimal, bool, Integer, Float10, NormalizedString, AnyURI, HexBinary, Base64Binary, QName, Duration, OrderedDateTime, Time] NumericValueType = Union[str, bytes, int, float, Decimal] DateTimeType = Union[OrderedDateTime, Time] ## # Type aliases for validation/decoding/encoding ConverterType = Union[Type[XMLSchemaConverter], XMLSchemaConverter] ExtraValidatorType = Callable[[ElementType, SchemaType], Optional[Iterator[XMLSchemaValidationError]]] D = TypeVar('D') DecodeType = Union[Optional[D], Tuple[Optional[D], List[XMLSchemaValidationError]]] IterDecodeType = Iterator[Union[D, XMLSchemaValidationError]] E = TypeVar('E') EncodeType = Union[E, Tuple[E, List[XMLSchemaValidationError]]] IterEncodeType = Iterator[Union[E, XMLSchemaValidationError]] JsonDecodeType = Union[str, None, Tuple[XMLSchemaValidationError, ...], Tuple[Union[str, None], Tuple[XMLSchemaValidationError, ...]]] DecodedValueType = Union[None, AtomicValueType, List[AtomicValueType]] EncodedValueType = Union[None, str, List[str]] else: # In runtime use a dummy subscriptable type for compatibility T = TypeVar('T') DummyType = Optional[T] module_globals = globals() for name in __all__: module_globals[name] = DummyType �����������������xmlschema-1.10.0/xmlschema/cli.py�������������������������������������������������������������������0000664�0000000�0000000�00000025537�14211403446�0016667�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """Command Line Interface""" import sys import os import argparse import logging import pathlib from urllib.error import URLError import xmlschema from xmlschema import XMLSchema, XMLSchema11, iter_errors, to_json, from_json from xmlschema.exceptions import XMLSchemaValueError from xmlschema.etree import etree_tostring PROGRAM_NAME = os.path.basename(sys.argv[0]) CONVERTERS_MAP = { 'Unordered': xmlschema.UnorderedConverter, 'Parker': xmlschema.ParkerConverter, 'BadgerFish': xmlschema.BadgerFishConverter, 'Abdera': xmlschema.AbderaConverter, 'JsonML': xmlschema.JsonMLConverter, 'Columnar': xmlschema.ColumnarConverter, } def xsd_version_number(value): if value not in ('1.0', '1.1'): raise argparse.ArgumentTypeError("%r is not a valid XSD version" % value) return value def defuse_data(value): if value not in ('always', 'remote', 'never'): raise argparse.ArgumentTypeError("%r is not a valid value" % value) return value def get_loglevel(verbosity): if verbosity <= 0: return logging.ERROR elif verbosity == 1: return logging.WARNING elif verbosity == 2: return logging.INFO else: return logging.DEBUG def get_converter(name): if name is None: return try: return CONVERTERS_MAP[name] except KeyError: raise ValueError("--converter must be in {!r}".format(tuple(CONVERTERS_MAP))) def xml2json(): parser = argparse.ArgumentParser(prog=PROGRAM_NAME, add_help=True, description="decode a set of XML files to JSON.") parser.usage = "%(prog)s [OPTION]... [FILE]...\n" \ "Try '%(prog)s --help' for more information." parser.add_argument('-v', dest='verbosity', action='count', default=0, help="increase output verbosity.") parser.add_argument('--schema', type=str, metavar='PATH', help="path or URL to an XSD schema.") parser.add_argument('--version', type=xsd_version_number, default='1.0', help="XSD schema validator to use (default is 1.0).") parser.add_argument('-L', dest='locations', nargs=2, type=str, action='append', metavar="URI/URL", help="schema location hint overrides.") parser.add_argument('--converter', type=str, metavar='NAME', help="use a different XML to JSON convention instead of " "the default converter. Option value can be one of " "{!r}.".format(tuple(CONVERTERS_MAP))) parser.add_argument('--lazy', action='store_true', default=False, help="use lazy decoding mode (slower but use less memory).") parser.add_argument('--defuse', metavar='(always, remote, never)', type=defuse_data, default='remote', help="when to defuse XML data, on remote resources for default.") parser.add_argument('-o', '--output', type=str, default='.', help="where to write the encoded XML files, current dir by default.") parser.add_argument('-f', '--force', action="store_true", default=False, help="do not prompt before overwriting.") parser.add_argument('files', metavar='[XML_FILE ...]', nargs='+', help="XML files to be decoded to JSON.") args = parser.parse_args() loglevel = get_loglevel(args.verbosity) schema_class = XMLSchema if args.version == '1.0' else XMLSchema11 converter = get_converter(args.converter) if args.schema is not None: schema = schema_class(args.schema, locations=args.locations, loglevel=loglevel) else: schema = None base_path = pathlib.Path(args.output) if not base_path.exists(): base_path.mkdir() elif not base_path.is_dir(): raise XMLSchemaValueError("{!r} is not a directory".format(str(base_path))) tot_errors = 0 for xml_path in map(pathlib.Path, args.files): json_path = base_path.joinpath(xml_path.name).with_suffix('.json') if json_path.exists() and not args.force: print("skip {}: the destination file exists!".format(str(json_path))) continue with open(str(json_path), 'w') as fp: try: errors = to_json( xml_document=str(xml_path), fp=fp, schema=schema, cls=schema_class, converter=converter, lazy=args.lazy, defuse=args.defuse, validation='lax', ) except (xmlschema.XMLSchemaException, URLError) as err: tot_errors += 1 print("error with {}: {}".format(str(xml_path), str(err))) continue else: if not errors: print("{} converted to {}".format(str(xml_path), str(json_path))) else: tot_errors += len(errors) print("{} converted to {} with {} errors".format( str(xml_path), str(json_path), len(errors) )) sys.exit(tot_errors) def json2xml(): parser = argparse.ArgumentParser(prog=PROGRAM_NAME, add_help=True, description="encode a set of JSON files to XML.") parser.usage = "%(prog)s [OPTION]... [FILE]...\n" \ "Try '%(prog)s --help' for more information." parser.add_argument('-v', dest='verbosity', action='count', default=0, help="increase output verbosity.") parser.add_argument('--schema', type=str, metavar='PATH', help="path or URL to an XSD schema.") parser.add_argument('--version', type=xsd_version_number, default='1.0', help="XSD schema validator to use (default is 1.0).") parser.add_argument('-L', dest='locations', nargs=2, type=str, action='append', metavar="URI/URL", help="schema location hint overrides.") parser.add_argument('--converter', type=str, metavar='NAME', help="use a different XML to JSON convention instead of " "the default converter. Option value can be one of " "{!r}.".format(tuple(CONVERTERS_MAP))) parser.add_argument('-o', '--output', type=str, default='.', help="where to write the encoded XML files, current dir by default.") parser.add_argument('-f', '--force', action="store_true", default=False, help="do not prompt before overwriting") parser.add_argument('files', metavar='[JSON_FILE ...]', nargs='+', help="JSON files to be encoded to XML.") args = parser.parse_args() loglevel = get_loglevel(args.verbosity) schema_class = XMLSchema if args.version == '1.0' else XMLSchema11 converter = get_converter(args.converter) schema = schema_class(args.schema, locations=args.locations, loglevel=loglevel) base_path = pathlib.Path(args.output) if not base_path.exists(): base_path.mkdir() elif not base_path.is_dir(): raise XMLSchemaValueError("{!r} is not a directory".format(str(base_path))) tot_errors = 0 for json_path in map(pathlib.Path, args.files): xml_path = base_path.joinpath(json_path.name).with_suffix('.xml') if xml_path.exists() and not args.force: print("skip {}: the destination file exists!".format(str(xml_path))) continue with open(str(json_path)) as fp: try: root, errors = from_json( source=fp, schema=schema, converter=converter, validation='lax', ) except (xmlschema.XMLSchemaException, URLError) as err: tot_errors += 1 print("error with {}: {}".format(str(xml_path), str(err))) continue else: if not errors: print("{} converted to {}".format(str(json_path), str(xml_path))) else: tot_errors += len(errors) print("{} converted to {} with {} errors".format( str(json_path), str(xml_path), len(errors) )) with open(str(xml_path), 'w') as fp: fp.write(etree_tostring(root)) sys.exit(tot_errors) def validate(): parser = argparse.ArgumentParser(prog=PROGRAM_NAME, add_help=True, description="validate a set of XML files.") parser.usage = "%(prog)s [OPTION]... [FILE]...\n" \ "Try '%(prog)s --help' for more information." parser.add_argument('-v', dest='verbosity', action='count', default=0, help="increase output verbosity.") parser.add_argument('--schema', type=str, metavar='PATH', help="path or URL to an XSD schema.") parser.add_argument('--version', type=xsd_version_number, default='1.0', help="XSD schema validator to use (default is 1.0).") parser.add_argument('-L', dest='locations', nargs=2, type=str, action='append', metavar="URI/URL", help="schema location hint overrides.") parser.add_argument('--lazy', action='store_true', default=False, help="use lazy validation mode (slower but use less memory).") parser.add_argument('--defuse', metavar='(always, remote, never)', type=defuse_data, default='remote', help="when to defuse XML data, on remote resources for default.") parser.add_argument('files', metavar='[XML_FILE ...]', nargs='+', help="XML files to be validated.") args = parser.parse_args() schema_class = XMLSchema if args.version == '1.0' else XMLSchema11 tot_errors = 0 for filepath in args.files: try: errors = list(iter_errors(filepath, schema=args.schema, cls=schema_class, locations=args.locations, lazy=args.lazy, defuse=args.defuse)) except (xmlschema.XMLSchemaException, URLError) as err: tot_errors += 1 print(str(err)) continue else: if not errors: print("{} is valid".format(filepath)) else: tot_errors += len(errors) print("{} is not valid".format(filepath)) sys.exit(tot_errors) �����������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/��������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017724�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/__init__.py���������������������������������������������������0000664�0000000�0000000�00000001421�14211403446�0022033�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from .default import XMLSchemaConverter from .unordered import UnorderedConverter from .parker import ParkerConverter from .badgerfish import BadgerFishConverter from .abdera import AbderaConverter from .jsonml import JsonMLConverter from .columnar import ColumnarConverter __all__ = ['XMLSchemaConverter', 'UnorderedConverter', 'ParkerConverter', 'BadgerFishConverter', 'AbderaConverter', 'JsonMLConverter', 'ColumnarConverter'] �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/abdera.py�����������������������������������������������������0000664�0000000�0000000�00000013673�14211403446�0021526�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, Any, Optional, List, Dict, Type, Union from ..exceptions import XMLSchemaValueError from ..etree import ElementData from ..aliases import NamespacesType, BaseXsdType from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class AbderaConverter(XMLSchemaConverter): """ XML Schema based converter class for Abdera convention. ref: http://wiki.open311.org/JSON_and_XML_Conversion/#the-abdera-convention ref: https://cwiki.apache.org/confluence/display/ABDERA/JSON+Serialization :param namespaces: Map from namespace prefixes to URI. :param dict_class: Dictionary class to use for decoded data. Default is `dict`. :param list_class: List class to use for decoded data. Default is `list`. """ __slots__ = () def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, **kwargs: Any) -> None: kwargs.update(attr_prefix='', text_key='', cdata_prefix=None) super(AbderaConverter, self).__init__( namespaces, dict_class, list_class, **kwargs ) @property def lossy(self) -> bool: return True # Loss cdata parts def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: xsd_type = xsd_type or xsd_element.type if xsd_type.simple_type is not None: children = data.text if data.text is not None and data.text != '' else None else: children = self.dict() for name, value, xsd_child in self.map_content(data.content): if value is None: value = self.list() try: children[name].append(value) except KeyError: if isinstance(value, MutableSequence) and value: children[name] = self.list([value]) else: children[name] = value except AttributeError: children[name] = self.list([children[name], value]) if not children: children = data.text if data.text is not None and data.text != '' else None if data.attributes: if children != []: return self.dict([ ('attributes', self.dict((k, v) for k, v in self.map_attributes(data.attributes))), ('children', self.list([children]) if children is not None else self.list()) ]) else: return self.dict([ ('attributes', self.dict((k, v) for k, v in self.map_attributes(data.attributes))), ]) else: return children if children is not None else self.list() def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: tag = xsd_element.qualified_name if level == 0 else xsd_element.name if not isinstance(obj, MutableMapping): if obj == []: obj = None return ElementData(tag, obj, None, {}) else: attributes: Dict[str, Any] = {} children: Union[List[Any], MutableMapping[str, Any]] try: attributes.update((self.unmap_qname(k, xsd_element.attributes), v) for k, v in obj['attributes'].items()) except KeyError: children = obj else: children = obj.get('children', []) if isinstance(children, MutableMapping): children = [children] elif children and not isinstance(children[0], MutableMapping): if len(children) > 1: raise XMLSchemaValueError("Wrong format") else: return ElementData(tag, children[0], None, attributes) content = [] for child in children: for name, value in child.items(): if not isinstance(value, MutableSequence) or not value: content.append((self.unmap_qname(name), value)) elif isinstance(value[0], (MutableMapping, MutableSequence)): ns_name = self.unmap_qname(name) for item in value: content.append((ns_name, item)) else: xsd_group = xsd_element.type.model_group if xsd_group is None: xsd_group = xsd_element.any_type.model_group assert xsd_group is not None ns_name = self.unmap_qname(name) for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content.append((ns_name, value)) else: content.extend((ns_name, item) for item in value) break else: content.append((ns_name, value)) return ElementData(tag, None, content, attributes) ���������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/badgerfish.py�������������������������������������������������0000664�0000000�0000000�00000014605�14211403446�0022402�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, Any, Optional, List, Dict, Type, Union, Tuple from ..etree import ElementData from ..aliases import NamespacesType, BaseXsdType from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class BadgerFishConverter(XMLSchemaConverter): """ XML Schema based converter class for Badgerfish convention. ref: http://www.sklar.com/badgerfish/ ref: http://badgerfish.ning.com/ :param namespaces: Map from namespace prefixes to URI. :param dict_class: Dictionary class to use for decoded data. Default is `dict`. :param list_class: List class to use for decoded data. Default is `list`. """ __slots__ = () def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, **kwargs: Any) -> None: kwargs.update(attr_prefix='@', text_key='$', cdata_prefix='$') super(BadgerFishConverter, self).__init__( namespaces, dict_class, list_class, **kwargs ) @property def lossy(self) -> bool: return False def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: xsd_type = xsd_type or xsd_element.type dict_class = self.dict tag = self.map_qname(data.tag) has_local_root = not self and not self.strip_namespaces result_dict = dict_class([t for t in self.map_attributes(data.attributes)]) if has_local_root: result_dict['@xmlns'] = dict_class() xsd_group = xsd_type.model_group if xsd_group is None: if data.text is not None and data.text != '': result_dict['$'] = data.text else: has_single_group = xsd_group.is_single() for name, value, xsd_child in self.map_content(data.content): try: if '@xmlns' in value: self.transfer(value['@xmlns']) if not value['@xmlns']: del value['@xmlns'] elif '@xmlns' in value[name]: self.transfer(value[name]['@xmlns']) if not value[name]['@xmlns']: del value[name]['@xmlns'] if len(value) == 1: value = value[name] except (TypeError, KeyError): pass if value is None: value = self.dict() try: result = result_dict[name] except KeyError: if xsd_child is None or has_single_group and xsd_child.is_single(): result_dict[name] = value else: result_dict[name] = self.list([value]) else: if not isinstance(result, MutableSequence) or not result: result_dict[name] = self.list([result, value]) elif isinstance(result[0], MutableSequence) or \ not isinstance(value, MutableSequence): result.append(value) else: result_dict[name] = self.list([result, value]) if has_local_root: if self: result_dict['@xmlns'].update(self) else: del result_dict['@xmlns'] return dict_class([(tag, result_dict)]) else: return dict_class([('@xmlns', dict_class(self)), (tag, result_dict)]) def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: tag = xsd_element.qualified_name if level == 0 else xsd_element.name if not self.strip_namespaces: try: self.update(obj['@xmlns']) except KeyError: pass try: element_data = obj[self.map_qname(xsd_element.name)] except KeyError: try: element_data = obj[xsd_element.name] except KeyError: element_data = obj text = None content: List[Tuple[Union[str, int], Any]] = [] attributes = {} for name, value in element_data.items(): if name == '@xmlns': continue elif name == '$': text = value elif name[0] == '$' and name[1:].isdigit(): content.append((int(name[1:]), value)) elif name[0] == '@': attr_name = name[1:] ns_name = self.unmap_qname(attr_name, xsd_element.attributes) attributes[ns_name] = value elif not isinstance(value, MutableSequence) or not value: content.append((self.unmap_qname(name), value)) elif isinstance(value[0], (MutableMapping, MutableSequence)): ns_name = self.unmap_qname(name) for item in value: content.append((ns_name, item)) else: xsd_group = xsd_element.type.model_group if xsd_group is None: xsd_group = xsd_element.any_type.model_group assert xsd_group is not None ns_name = self.unmap_qname(name) for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content.append((ns_name, value)) else: content.extend((ns_name, item) for item in value) break else: content.append((ns_name, value)) return ElementData(tag, text, content, attributes) ���������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/columnar.py���������������������������������������������������0000664�0000000�0000000�00000016642�14211403446�0022127�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, Any, Optional, List, Dict, Type, Tuple from ..exceptions import XMLSchemaTypeError, XMLSchemaValueError from ..etree import ElementData from ..aliases import NamespacesType, BaseXsdType from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class ColumnarConverter(XMLSchemaConverter): """ XML Schema based converter class for columnar formats. :param namespaces: map from namespace prefixes to URI. :param dict_class: dictionary class to use for decoded data. Default is `dict`. :param list_class: list class to use for decoded data. Default is `list`. :param attr_prefix: used as separator string for renaming the decoded attributes. \ Can be the empty string (the default) or a single/double underscore. """ __slots__ = () def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, attr_prefix: Optional[str] = '', **kwargs: Any) -> None: kwargs.update(text_key=None, cdata_prefix=None) super(ColumnarConverter, self).__init__(namespaces, dict_class, list_class, attr_prefix=attr_prefix, **kwargs) @property def lossy(self) -> bool: return True # Loss cdata parts def __setattr__(self, name: str, value: Any) -> None: if name != 'attr_prefix': super(ColumnarConverter, self).__setattr__(name, value) elif not isinstance(value, str): msg = '{} must be a str, not {}' raise XMLSchemaTypeError(msg.format(name, type(value).__name__)) elif value not in {'', '_', '__'}: msg = '{} can be the empty string or a single/double underscore' raise XMLSchemaValueError(msg.format(name)) else: super(XMLSchemaConverter, self).__setattr__(name, value) def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: result_dict: Any xsd_type = xsd_type or xsd_element.type if data.attributes: if self.attr_prefix: pfx = xsd_element.local_name + self.attr_prefix else: pfx = xsd_element.local_name result_dict = self.dict((pfx + self.map_qname(k), v) for k, v in data.attributes) else: result_dict = self.dict() if xsd_type.simple_type is not None: result_dict[xsd_element.local_name] = data.text or None if data.content: for name, value, xsd_child in self.map_content(data.content): if not value: continue elif xsd_child.local_name: name = xsd_child.local_name else: name = name[2 + len(xsd_child.namespace):] if xsd_child.is_single(): if xsd_child.type is not None and xsd_child.type.simple_type is not None: for k in value: result_dict[k] = value[k] else: result_dict[name] = value else: if xsd_child.type is not None and xsd_child.type.simple_type is not None \ and not xsd_child.attributes: if len(xsd_element.findall('*')) == 1: try: result_dict.append(list(value.values())[0]) except AttributeError: result_dict = self.list(value.values()) else: try: result_dict[name].append(list(value.values())[0]) except KeyError: result_dict[name] = self.list(value.values()) except AttributeError: result_dict[name] = self.list(value.values()) else: try: result_dict[name].append(value) except KeyError: result_dict[name] = self.list([value]) except AttributeError: result_dict[name] = self.list([value]) if level == 0: return self.dict([(xsd_element.local_name, result_dict)]) else: return result_dict def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: if level != 0: tag = xsd_element.local_name else: tag = xsd_element.local_name try: obj = obj[tag] except (KeyError, AttributeError, TypeError): pass if not isinstance(obj, MutableMapping): if xsd_element.type.simple_type is not None: return ElementData(xsd_element.name, obj, None, {}) elif xsd_element.type.mixed and not isinstance(obj, MutableSequence): return ElementData(xsd_element.name, obj, None, {}) else: return ElementData(xsd_element.name, None, obj, {}) text = None content: List[Tuple[Optional[str], MutableSequence[Any]]] = [] attributes = {} pfx = tag + self.attr_prefix if self.attr_prefix else tag for name, value in obj.items(): if name == tag: text = value elif name.startswith(pfx) and len(name) > len(pfx): attr_name = name[len(pfx):] ns_name = self.unmap_qname(attr_name, xsd_element.attributes) attributes[ns_name] = value elif not isinstance(value, MutableSequence) or not value: content.append((self.unmap_qname(name), value)) elif isinstance(value[0], (MutableMapping, MutableSequence)): ns_name = self.unmap_qname(name) content.extend((ns_name, item) for item in value) else: xsd_group = xsd_element.type.model_group if xsd_group is None: xsd_group = xsd_element.any_type.model_group assert xsd_group is not None ns_name = self.unmap_qname(name) for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content.append((xsd_child.name, value)) else: content.extend((xsd_child.name, item) for item in value) break else: content.append((ns_name, value)) return ElementData(xsd_element.name, text, content, attributes) ����������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/default.py����������������������������������������������������0000664�0000000�0000000�00000045662�14211403446�0021737�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, cast, Any, Dict, Iterator, Iterable, \ List, Optional, Type, Tuple, Union from ..exceptions import XMLSchemaTypeError from ..names import XSI_NAMESPACE from ..etree import etree_element, ElementData from ..aliases import NamespacesType, ElementType, BaseXsdType from ..namespaces import NamespaceMapper if TYPE_CHECKING: from ..validators import XsdElement class XMLSchemaConverter(NamespaceMapper): """ Generic XML Schema based converter class. A converter is used to compose decoded XML data for an Element into a data structure and to build an Element from encoded data structure. There are two methods for interfacing the converter with the decoding/encoding process. The method *element_decode* accepts an ElementData tuple, containing the element parts, and returns a data structure. The method *element_encode* accepts a data structure and returns an ElementData tuple. For default character data parts are ignored. Prefixes and text key can be changed also using alphanumeric values but ambiguities with schema elements could affect XML data re-encoding. :param namespaces: map from namespace prefixes to URI. :param dict_class: dictionary class to use for decoded data. Default is `dict`. :param list_class: list class to use for decoded data. Default is `list`. :param etree_element_class: the class that has to be used to create new XML elements, \ if not provided uses the ElementTree's Element class. :param text_key: is the key to apply to element's decoded text data. :param attr_prefix: controls the mapping of XML attributes, to the same name or \ with a prefix. If `None` the converter ignores attributes. :param cdata_prefix: is used for including and prefixing the character data parts \ of a mixed content, that are labeled with an integer instead of a string. \ Character data parts are ignored if this argument is `None`. :param indent: number of spaces for XML indentation (default is 4). :param strip_namespaces: if set to `True` removes namespace declarations from data and \ namespace information from names, during decoding or encoding. Defaults to `False`. :param preserve_root: if set to `True` the root element is preserved, wrapped into a \ single-item dictionary. Applicable only to default converter, to \ :class:`UnorderedConverter` and to :class:`ParkerConverter`. :param force_dict: if set to `True` complex elements with simple content are decoded \ with a dictionary also if there are no decoded attributes. Applicable only to default \ converter and to :class:`UnorderedConverter`. Defaults to `False`. :param force_list: if set to `True` child elements are decoded within a list in any case. \ Applicable only to default converter and to :class:`UnorderedConverter`. Defaults to `False`. :ivar dict: dictionary class to use for decoded data. :ivar list: list class to use for decoded data. :ivar etree_element_class: Element class to use :ivar text_key: key for decoded Element text :ivar attr_prefix: prefix for attribute names :ivar cdata_prefix: prefix for character data parts :ivar indent: indentation to use for rebuilding XML trees :ivar preserve_root: preserve the root element on decoding :ivar force_dict: force dictionary for complex elements with simple content :ivar force_list: force list for child elements """ ns_prefix: str dict: Type[Dict[str, Any]] = dict list: Type[List[Any]] = list etree_element_class: Type[ElementType] etree_element_class = etree_element __slots__ = ('text_key', 'ns_prefix', 'attr_prefix', 'cdata_prefix', 'indent', 'preserve_root', 'force_dict', 'force_list') def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, etree_element_class: Optional[Type[ElementType]] = None, text_key: Optional[str] = '$', attr_prefix: Optional[str] = '@', cdata_prefix: Optional[str] = None, indent: int = 4, strip_namespaces: bool = False, preserve_root: bool = False, force_dict: bool = False, force_list: bool = False, **kwargs: Any) -> None: super(XMLSchemaConverter, self).__init__(namespaces, strip_namespaces) if dict_class is not None: self.dict = dict_class if list_class is not None: self.list = list_class if etree_element_class is not None: self.etree_element_class = etree_element_class self.text_key = text_key self.attr_prefix = attr_prefix self.cdata_prefix = cdata_prefix self.ns_prefix = 'xmlns' if attr_prefix is None else f'{attr_prefix}xmlns' self.indent = indent self.preserve_root = preserve_root self.force_dict = force_dict self.force_list = force_list def __setattr__(self, name: str, value: Any) -> None: if name in {'attr_prefix', 'text_key', 'cdata_prefix'}: if value is not None and not isinstance(value, str): msg = '{} must be a str or None, not {}' raise XMLSchemaTypeError(msg.format(name, type(value).__name__)) elif name in {'strip_namespaces', 'preserve_root', 'force_dict', 'force_list'}: if not isinstance(value, bool): msg = '{} must be a bool, not {}' raise XMLSchemaTypeError(msg.format(name, type(value).__name__)) elif name == 'indent': if isinstance(value, bool) or not isinstance(value, int): msg = '{} must be an int, not {}' raise XMLSchemaTypeError(msg.format(name, type(value).__name__)) elif name == 'dict': if not issubclass(value, MutableMapping): msg = '{!r} must be a MutableMapping subclass, not {}' raise XMLSchemaTypeError(msg.format(name, value)) elif name == 'list': if not issubclass(value, MutableSequence): msg = '{!r} must be a MutableSequence subclass, not {}' raise XMLSchemaTypeError(msg.format(name, value)) super(XMLSchemaConverter, self).__setattr__(name, value) @property def lossy(self) -> bool: """The converter ignores some kind of XML data during decoding/encoding.""" return self.cdata_prefix is None or self.text_key is None or self.attr_prefix is None @property def losslessly(self) -> bool: """ The XML data is decoded without loss of quality, neither on data nor on data model shape. Only losslessly converters can be always used to encode to an XML data that is strictly conformant to the schema. """ return False def copy(self, **kwargs: Any) -> 'XMLSchemaConverter': return type(self)( namespaces=kwargs.get('namespaces', self._namespaces), dict_class=kwargs.get('dict_class', self.dict), list_class=kwargs.get('list_class', self.list), etree_element_class=kwargs.get('etree_element_class'), text_key=kwargs.get('text_key', self.text_key), attr_prefix=kwargs.get('attr_prefix', self.attr_prefix), cdata_prefix=kwargs.get('cdata_prefix', self.cdata_prefix), indent=kwargs.get('indent', self.indent), strip_namespaces=kwargs.get('strip_namespaces', self.strip_namespaces), preserve_root=kwargs.get('preserve_root', self.preserve_root), force_dict=kwargs.get('force_dict', self.force_dict), force_list=kwargs.get('force_list', self.force_list), ) def map_attributes(self, attributes: Iterable[Tuple[str, Any]]) \ -> Iterator[Tuple[str, Any]]: """ Creates an iterator for converting decoded attributes to a data structure with appropriate prefixes. If the instance has a not-empty map of namespaces registers the mapped URIs and prefixes. :param attributes: A sequence or an iterator of couples with the name of \ the attribute and the decoded value. Default is `None` (for `simpleType` \ elements, that don't have attributes). """ if self.attr_prefix is None or not attributes: return elif self.attr_prefix: for name, value in attributes: yield '%s%s' % (self.attr_prefix, self.map_qname(name)), value else: for name, value in attributes: yield self.map_qname(name), value def map_content(self, content: Iterable[Tuple[str, Any, Any]]) \ -> Iterator[Tuple[str, Any, Any]]: """ A generator function for converting decoded content to a data structure. If the instance has a not-empty map of namespaces registers the mapped URIs and prefixes. :param content: A sequence or an iterator of tuples with the name of the \ element, the decoded value and the `XsdElement` instance associated. """ if not content: return for name, value, xsd_child in content: try: if name[0] == '{': yield self.map_qname(name), value, xsd_child else: yield name, value, xsd_child except TypeError: if self.cdata_prefix is not None: yield '%s%s' % (self.cdata_prefix, name), value, xsd_child def etree_element(self, tag: str, text: Optional[str] = None, children: Optional[List[ElementType]] = None, attrib: Optional[Dict[str, str]] = None, level: int = 0) -> ElementType: """ Builds an ElementTree's Element using arguments and the element class and the indent spacing stored in the converter instance. :param tag: the Element tag string. :param text: the Element text. :param children: the list of Element children/subelements. :param attrib: a dictionary with Element attributes. :param level: the level related to the encoding process (0 means the root). :return: an instance of the Element class is set for the converter instance. """ if type(self.etree_element_class) is type(etree_element): if attrib is None: elem = self.etree_element_class(tag) else: elem = self.etree_element_class(tag, self.dict(attrib)) else: # FIXME: need a more refined check nsmap = {prefix if prefix else None: uri for prefix, uri in self._namespaces.items() if uri} elem = self.etree_element_class(tag, nsmap=nsmap) # type: ignore[arg-type] elem.attrib.update(attrib) # type: ignore[arg-type] if children: elem.extend(children) elem.text = text or '\n' + ' ' * self.indent * (level + 1) elem.tail = '\n' + ' ' * self.indent * level else: elem.text = text elem.tail = '\n' + ' ' * self.indent * level return elem def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: """ Converts a decoded element data to a data structure. :param data: ElementData instance decoded from an Element node. :param xsd_element: the `XsdElement` associated to decoded the data. :param xsd_type: optional XSD type for supporting dynamic type through \ *xsi:type* or xs:alternative. :param level: the level related to the decoding process (0 means the root). :return: a data structure containing the decoded data. """ xsd_type = xsd_type or xsd_element.type result_dict = self.dict() if level == 0 and xsd_element.is_global() and not self.strip_namespaces and self: schema_namespaces = set(xsd_element.namespaces.values()) result_dict.update( ('%s:%s' % (self.ns_prefix, k) if k else self.ns_prefix, v) for k, v in self._namespaces.items() if v in schema_namespaces or v == XSI_NAMESPACE ) xsd_group = xsd_type.model_group if xsd_group is None: if data.attributes or self.force_dict and not xsd_type.is_simple(): result_dict.update(t for t in self.map_attributes(data.attributes)) if data.text is not None and data.text != '' and self.text_key is not None: result_dict[self.text_key] = data.text return result_dict else: return data.text if data.text != '' else None else: if data.attributes: result_dict.update(t for t in self.map_attributes(data.attributes)) has_single_group = xsd_group.is_single() if data.content: for name, value, xsd_child in self.map_content(data.content): try: result = result_dict[name] except KeyError: if xsd_child is None or has_single_group and xsd_child.is_single(): result_dict[name] = self.list([value]) if self.force_list else value else: result_dict[name] = self.list([value]) else: if not isinstance(result, MutableSequence) or not result: result_dict[name] = self.list([result, value]) elif isinstance(result[0], MutableSequence) or \ not isinstance(value, MutableSequence): result.append(value) else: result_dict[name] = self.list([result, value]) elif data.text is not None and data.text != '' and self.text_key is not None: result_dict[self.text_key] = data.text if level == 0 and self.preserve_root: return self.dict( [(self.map_qname(data.tag), result_dict if result_dict else None)] ) if not result_dict: return None elif len(result_dict) == 1 and self.text_key in result_dict: return result_dict[self.text_key] return result_dict def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: """ Extracts XML decoded data from a data structure for encoding into an ElementTree. :param obj: the decoded object. :param xsd_element: the `XsdElement` associated to the decoded data structure. :param level: the level related to the encoding process (0 means the root). :return: an ElementData instance. """ if level != 0: tag = xsd_element.name else: if xsd_element.is_global(): tag = xsd_element.qualified_name else: tag = xsd_element.name if self.preserve_root and isinstance(obj, MutableMapping): match_local_name = cast(bool, self.strip_namespaces or self.default_namespace) match = xsd_element.get_matching_item(obj, self.ns_prefix, match_local_name) if match is not None: obj = match if not isinstance(obj, MutableMapping): if xsd_element.type.simple_type is not None: return ElementData(tag, obj, None, {}) elif xsd_element.type.mixed and isinstance(obj, (str, bytes)): return ElementData(tag, None, [(1, obj)], {}) else: return ElementData(tag, None, obj, {}) text = None content: List[Tuple[Union[int, str], Any]] = [] attributes = {} for name, value in obj.items(): if name == self.text_key: text = value elif self.cdata_prefix is not None and \ name.startswith(self.cdata_prefix) and \ name[len(self.cdata_prefix):].isdigit(): index = int(name[len(self.cdata_prefix):]) content.append((index, value)) elif name == self.ns_prefix: self[''] = value elif name.startswith('%s:' % self.ns_prefix): if not self.strip_namespaces: self[name[len(self.ns_prefix) + 1:]] = value elif self.attr_prefix and \ name.startswith(self.attr_prefix) and \ name != self.attr_prefix: attr_name = name[len(self.attr_prefix):] ns_name = self.unmap_qname(attr_name, xsd_element.attributes) attributes[ns_name] = value elif not isinstance(value, MutableSequence) or not value: content.append((self.unmap_qname(name), value)) elif isinstance(value[0], (MutableMapping, MutableSequence)): ns_name = self.unmap_qname(name) content.extend((ns_name, item) for item in value) else: xsd_group = xsd_element.type.model_group if xsd_group is None: # fallback to xs:anyType encoder xsd_group = xsd_element.any_type.model_group assert xsd_group is not None ns_name = self.unmap_qname(name) for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content.append((ns_name, value)) else: content.extend((ns_name, item) for item in value) break else: if self.attr_prefix == '' and ns_name not in attributes: for key, xsd_attribute in xsd_element.attributes.items(): if key and xsd_attribute.is_matching(ns_name): attributes[key] = value break else: content.append((ns_name, value)) else: content.append((ns_name, value)) return ElementData(tag, text, content, attributes) ������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/jsonml.py�����������������������������������������������������0000664�0000000�0000000�00000011113�14211403446�0021575�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableSequence from typing import TYPE_CHECKING, Any, Optional, List, Dict, Type from ..exceptions import XMLSchemaValueError from ..etree import ElementData from ..aliases import NamespacesType, BaseXsdType from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class JsonMLConverter(XMLSchemaConverter): """ XML Schema based converter class for JsonML (JSON Mark-up Language) convention. ref: http://www.jsonml.org/ ref: https://www.ibm.com/developerworks/library/x-jsonml/ :param namespaces: Map from namespace prefixes to URI. :param dict_class: Dictionary class to use for decoded data. Default is `dict`. :param list_class: List class to use for decoded data. Default is `list`. """ __slots__ = () def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, **kwargs: Any) -> None: kwargs.update(attr_prefix='', text_key='', cdata_prefix='') super(JsonMLConverter, self).__init__( namespaces, dict_class, list_class, **kwargs ) @property def lossy(self) -> bool: return False @property def losslessly(self) -> bool: return True def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: xsd_type = xsd_type or xsd_element.type result_list = self.list() result_list.append(self.map_qname(data.tag)) if data.text is not None and data.text != '': result_list.append(data.text) if xsd_type.model_group is not None: result_list.extend([ value if value is not None else self.list([name]) for name, value, _ in self.map_content(data.content) ]) attributes = self.dict((k, v) for k, v in self.map_attributes(data.attributes)) if level == 0 and xsd_element.is_global() and not self.strip_namespaces and self: attributes.update( ('xmlns:%s' % k if k else 'xmlns', v) for k, v in self._namespaces.items() ) if attributes: result_list.insert(1, attributes) return result_list def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: attributes: Dict[str, Any] = {} if not isinstance(obj, MutableSequence) or not obj: raise XMLSchemaValueError("Wrong data format, a not empty list required: %r." % obj) data_len = len(obj) if data_len == 1: if not xsd_element.is_matching(self.unmap_qname(obj[0]), self._namespaces.get('')): raise XMLSchemaValueError("Unmatched tag") return ElementData(xsd_element.name, None, None, attributes) try: for k, v in obj[1].items(): if k == 'xmlns': self[''] = v elif k.startswith('xmlns:'): self[k.split('xmlns:')[1]] = v for k, v in obj[1].items(): if k != 'xmlns' and not k.startswith('xmlns:'): attributes[self.unmap_qname(k, xsd_element.attributes)] = v except AttributeError: content_index = 1 else: content_index = 2 if not xsd_element.is_matching(self.unmap_qname(obj[0]), self._namespaces.get('')): raise XMLSchemaValueError("Unmatched tag") if data_len <= content_index: return ElementData(xsd_element.name, None, [], attributes) elif data_len == content_index + 1 and \ (xsd_element.type.simple_type is not None or not xsd_element.type.content and xsd_element.type.mixed): return ElementData(xsd_element.name, obj[content_index], [], attributes) else: cdata_num = iter(range(1, data_len)) content = [ (self.unmap_qname(e[0]), e) if isinstance(e, MutableSequence) else (next(cdata_num), e) for e in obj[content_index:] ] return ElementData(xsd_element.name, None, content, attributes) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/parker.py�����������������������������������������������������0000664�0000000�0000000�00000013400�14211403446�0021560�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, Any, Optional, List, Dict, Type from ..etree import ElementData from ..aliases import NamespacesType, BaseXsdType from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class ParkerConverter(XMLSchemaConverter): """ XML Schema based converter class for Parker convention. ref: http://wiki.open311.org/JSON_and_XML_Conversion/#the-parker-convention ref: https://developer.mozilla.org/en-US/docs/Archive/JXON#The_Parker_Convention :param namespaces: Map from namespace prefixes to URI. :param dict_class: Dictionary class to use for decoded data. Default is `dict`. :param list_class: List class to use for decoded data. Default is `list`. :param preserve_root: If `True` the root element will be preserved. For default \ the Parker convention remove the document root element, returning only the value. """ __slots__ = () def __init__(self, namespaces: Optional[NamespacesType] = None, dict_class: Optional[Type[Dict[str, Any]]] = None, list_class: Optional[Type[List[Any]]] = None, preserve_root: bool = False, **kwargs: Any) -> None: kwargs.update(attr_prefix=None, text_key='', cdata_prefix=None) super(ParkerConverter, self).__init__( namespaces, dict_class, list_class, preserve_root=preserve_root, **kwargs ) @property def lossy(self) -> bool: return True def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> Any: xsd_type = xsd_type or xsd_element.type preserve_root = self.preserve_root if xsd_type.simple_type is not None: if preserve_root: return self.dict([(self.map_qname(data.tag), data.text)]) else: return data.text if data.text != '' else None else: result_dict = self.dict() for name, value, xsd_child in self.map_content(data.content): if preserve_root: try: if len(value) == 1: value = value[name] except (TypeError, KeyError): pass try: result_dict[name].append(value) except KeyError: if isinstance(value, MutableSequence): result_dict[name] = self.list([value]) else: result_dict[name] = value except AttributeError: result_dict[name] = self.list([result_dict[name], value]) for k, v in result_dict.items(): if isinstance(v, MutableSequence) and len(v) == 1: value = v.pop() v.extend(value) if preserve_root: return self.dict([(self.map_qname(data.tag), result_dict)]) else: return result_dict if result_dict else None def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: name: str = xsd_element.name if not isinstance(obj, MutableMapping): if obj == '': obj = None if xsd_element.type.simple_type is not None: return ElementData(xsd_element.name, obj, None, {}) else: return ElementData(xsd_element.name, None, obj, {}) else: if not obj: return ElementData(xsd_element.name, None, None, {}) elif self.preserve_root: try: items = obj[self.map_qname(name)] except KeyError: return ElementData(xsd_element.name, None, None, {}) else: items = obj try: xsd_group = xsd_element.type.model_group if xsd_group is None: xsd_group = xsd_element.any_type.model_group assert xsd_group is not None content = [] for name, value in obj.items(): ns_name = self.unmap_qname(name) if not isinstance(value, MutableSequence) or not value: content.append((ns_name, value)) elif any(isinstance(v, MutableSequence) for v in value): for item in value: content.append((ns_name, item)) else: for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content.append((ns_name, value)) else: content.extend((ns_name, item) for item in value) break else: content.extend((ns_name, item) for item in value) except AttributeError: return ElementData(xsd_element.name, items, None, {}) else: return ElementData(xsd_element.name, None, content, {}) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/converters/unordered.py��������������������������������������������������0000664�0000000�0000000�00000013121�14211403446�0022263�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableMapping, MutableSequence from typing import TYPE_CHECKING, cast, Any, Dict, Union from ..etree import ElementData from .default import XMLSchemaConverter if TYPE_CHECKING: from ..validators import XsdElement class UnorderedConverter(XMLSchemaConverter): """ Same as :class:`XMLSchemaConverter` but :meth:`element_encode` returns a dictionary for the content of the element, that can be used directly for unordered encoding mode. In this mode the order of the elements in the encoded output is based on the model visitor pattern rather than the order in which the elements were added to the input dictionary. As the order of the input dictionary is not preserved, character data between sibling elements are interleaved between tags. """ __slots__ = () def element_encode(self, obj: Any, xsd_element: 'XsdElement', level: int = 0) -> ElementData: """ Extracts XML decoded data from a data structure for encoding into an ElementTree. :param obj: the decoded object. :param xsd_element: the `XsdElement` associated to the decoded data structure. :param level: the level related to the encoding process (0 means the root). :return: an ElementData instance. """ if level: tag = xsd_element.name else: tag = xsd_element.qualified_name if self.preserve_root and isinstance(obj, MutableMapping): match_local_name = cast(bool, self.strip_namespaces or self.default_namespace) match = xsd_element.get_matching_item(obj, self.ns_prefix, match_local_name) if match is not None: obj = match if not isinstance(obj, MutableMapping): if xsd_element.type.simple_type is not None: return ElementData(tag, obj, None, {}) elif xsd_element.type.mixed and isinstance(obj, (str, bytes)): return ElementData(tag, None, [(1, obj)], {}) else: return ElementData(tag, None, obj, {}) text = None attributes = {} # The unordered encoding mode assumes that the values of this dict will # all be lists where each item is the content of a single element. When # building content_lu, content which is not a list or lists to be placed # into a single element (element has a list content type) must be wrapped # in a list to retain that structure. Character data are not wrapped into # lists because they because they are divided from the rest of the content # into the unordered mode generator function of the ModelVisitor class. content_lu: Dict[Union[int, str], Any] = {} for name, value in obj.items(): if name == self.text_key: text = value elif self.cdata_prefix is not None and \ name.startswith(self.cdata_prefix) and \ name[len(self.cdata_prefix):].isdigit(): index = int(name[len(self.cdata_prefix):]) content_lu[index] = value elif name == self.ns_prefix: self[''] = value elif name.startswith('%s:' % self.ns_prefix): self[name[len(self.ns_prefix) + 1:]] = value elif self.attr_prefix and \ name.startswith(self.attr_prefix) and \ name != self.attr_prefix: attr_name = name[len(self.attr_prefix):] ns_name = self.unmap_qname(attr_name, xsd_element.attributes) attributes[ns_name] = value elif not isinstance(value, MutableSequence) or not value: content_lu[self.unmap_qname(name)] = [value] elif isinstance(value[0], (MutableMapping, MutableSequence)): content_lu[self.unmap_qname(name)] = value else: xsd_group = xsd_element.type.model_group if xsd_group is None: xsd_group = xsd_element.any_type.model_group assert xsd_group is not None # `value` is a list but not a list of lists or list of dicts. ns_name = self.unmap_qname(name) for xsd_child in xsd_group.iter_elements(): matched_element = xsd_child.match(ns_name, resolve=True) if matched_element is not None: if matched_element.type and matched_element.type.is_list(): content_lu[self.unmap_qname(name)] = [value] else: content_lu[self.unmap_qname(name)] = value break else: if self.attr_prefix == '' and ns_name not in attributes: for xsd_attribute in xsd_element.attributes.values(): if xsd_attribute.is_matching(ns_name): attributes[ns_name] = value break else: content_lu[self.unmap_qname(name)] = [value] else: content_lu[self.unmap_qname(name)] = [value] return ElementData(tag, text, content_lu, attributes) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/dataobjects.py�����������������������������������������������������������0000664�0000000�0000000�00000046316�14211403446�0020401�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import sys if sys.version_info < (3, 7): from typing import GenericMeta as ABCMeta else: from abc import ABCMeta from itertools import count from typing import TYPE_CHECKING, cast, overload, Any, Dict, List, Iterator, \ Optional, Union, Tuple, Type, MutableMapping, MutableSequence from elementpath import XPathContext, XPath2Parser from .exceptions import XMLSchemaAttributeError, XMLSchemaTypeError, XMLSchemaValueError from .etree import ElementData, etree_tostring from .aliases import ElementType, XMLSourceType, NamespacesType, BaseXsdType, DecodeType from .helpers import get_namespace, get_prefixed_qname, local_name, raw_xml_encode from .converters import XMLSchemaConverter from .resources import XMLResource from . import validators if TYPE_CHECKING: from .validators import XMLSchemaValidationError, XsdElement class DataElement(MutableSequence['DataElement']): """ Data Element, an Element like object with decoded data and schema bindings. :param tag: a string containing a QName in extended format. :param value: the simple typed value of the element. :param attrib: the typed attributes of the element. :param nsmap: an optional map from prefixes to namespaces. :param xsd_element: an optional XSD element association. :param xsd_type: an optional XSD type association. Can be provided \ also if the instance is not bound with an XSD element. """ _children: List['DataElement'] tag: str attrib: Dict[str, Any] nsmap: Dict[str, str] value: Optional[Any] = None tail: Optional[str] = None xsd_element: Optional['XsdElement'] = None xsd_type: Optional[BaseXsdType] = None _encoder: Optional['XsdElement'] = None def __init__(self, tag: str, value: Optional[Any] = None, attrib: Optional[Dict[str, Any]] = None, nsmap: Optional[MutableMapping[str, str]] = None, xsd_element: Optional['XsdElement'] = None, xsd_type: Optional[BaseXsdType] = None) -> None: super(DataElement, self).__init__() self._children = [] self.tag = tag self.attrib = {} self.nsmap = {} if value is not None: self.value = value if attrib is not None: self.attrib.update(attrib) if nsmap is not None: self.nsmap.update(nsmap) if xsd_element is not None: self.xsd_element = xsd_element self.xsd_type = xsd_type or xsd_element.type elif xsd_type is not None: self.xsd_type = xsd_type elif self.xsd_element is not None: self._encoder = self.xsd_element @overload def __getitem__(self, i: int) -> 'DataElement': ... @overload def __getitem__(self, s: slice) -> MutableSequence['DataElement']: ... def __getitem__(self, i: Union[int, slice]) \ -> Union['DataElement', MutableSequence['DataElement']]: return self._children[i] def __setitem__(self, i: Union[int, slice], child: Any) -> None: self._children[i] = child def __delitem__(self, i: Union[int, slice]) -> None: del self._children[i] def __len__(self) -> int: return len(self._children) def insert(self, i: int, child: 'DataElement') -> None: assert isinstance(child, DataElement) self._children.insert(i, child) def __repr__(self) -> str: return '%s(tag=%r)' % (self.__class__.__name__, self.tag) def __iter__(self) -> Iterator['DataElement']: yield from self._children def __setattr__(self, key: str, value: Any) -> None: if key == 'xsd_element': if not isinstance(value, validators.XsdElement): raise XMLSchemaTypeError("invalid type for attribute 'xsd_element'") elif self.xsd_element is value: pass elif self.xsd_element is not None: raise XMLSchemaValueError("the instance is already bound to another XSD element") elif self.xsd_type is not None and self.xsd_type is not value.type: raise XMLSchemaValueError("the instance is already bound to another XSD type") elif key == 'xsd_type': if not isinstance(value, (validators.XsdSimpleType, validators.XsdComplexType)): raise XMLSchemaTypeError("invalid type for attribute 'xsd_type'") elif self.xsd_type is not None and self.xsd_type is not value: raise XMLSchemaValueError("the instance is already bound to another XSD type") elif self.xsd_element is None or value is not self.xsd_element.type: self._encoder = value.schema.create_element( self.tag, parent=value, form='unqualified' ) self._encoder.type = value else: self._encoder = self.xsd_element super(DataElement, self).__setattr__(key, value) @property def text(self) -> Optional[str]: """The string value of the data element.""" return raw_xml_encode(self.value) def get(self, key: str, default: Any = None) -> Any: """Gets a data element attribute.""" return self.attrib.get(key, default) def set(self, key: str, value: Any) -> None: """Sets a data element attribute.""" self.attrib[key] = value @property def xsd_version(self) -> str: return '1.0' if self.xsd_element is None else self.xsd_element.xsd_version @property def namespace(self) -> str: """The element's namespace.""" if self.xsd_element is None: return get_namespace(self.tag) return get_namespace(self.tag) or self.xsd_element.target_namespace @property def name(self) -> str: """The element's name, that matches the tag.""" return self.tag @property def prefixed_name(self) -> str: """The prefixed name, or the tag if no prefix is defined for its namespace.""" return get_prefixed_qname(self.tag, self.nsmap) @property def local_name(self) -> str: """The local part of the tag.""" return local_name(self.tag) def validate(self, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None) -> None: """ Validates the XML data object. :param use_defaults: whether to use default values for filling missing data. :param namespaces: is an optional mapping from namespace prefix to URI. \ For default uses the namespace map of the XML data object. :param max_depth: maximum depth for validation, for default there is no limit. :raises: :exc:`XMLSchemaValidationError` if XML data object is not valid. :raises: :exc:`XMLSchemaValueError` if the instance has no schema bindings. """ for error in self.iter_errors(use_defaults, namespaces, max_depth): raise error def is_valid(self, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None) -> bool: """ Like :meth:`validate` except it does not raise an exception on validation error but returns ``True`` if the XML data object is valid, ``False`` if it's invalid. :raises: :exc:`XMLSchemaValueError` if the instance has no schema bindings. """ error = next(self.iter_errors(use_defaults, namespaces, max_depth), None) return error is None def iter_errors(self, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None) -> Iterator['XMLSchemaValidationError']: """ Generates a sequence of validation errors if the XML data object is invalid. Accepts the same arguments of :meth:`validate`. """ if self._encoder is None: raise XMLSchemaValueError("{!r} has no schema bindings".format(self)) kwargs: Dict[str, Any] = { 'converter': DataElementConverter, 'use_defaults': use_defaults, } if namespaces: kwargs['namespaces'] = namespaces if isinstance(max_depth, int) and max_depth >= 0: kwargs['max_depth'] = max_depth for result in self._encoder.iter_encode(self, **kwargs): if isinstance(result, validators.XMLSchemaValidationError): yield result else: del result def encode(self, validation: str = 'strict', **kwargs: Any) \ -> Union[ElementType, Tuple[ElementType, List['XMLSchemaValidationError']]]: """ Encodes the data object to XML. :param validation: the validation mode. Can be 'lax', 'strict' or 'skip. :param kwargs: optional keyword arguments for the method :func:`iter_encode` \ of :class:`XsdElement`. :return: An ElementTree's Element. If *validation* argument is 'lax' a \ 2-items tuple is returned, where the first item is the encoded object and \ the second item is a list with validation errors. :raises: :exc:`XMLSchemaValidationError` if the object is invalid \ and ``validation='strict'``. """ if 'converter' not in kwargs: kwargs['converter'] = DataElementConverter encoder: Union['XsdElement', BaseXsdType] if self._encoder is not None: encoder = self._encoder elif validation == 'skip': encoder = validators.XMLSchema.builtin_types()['anyType'] else: raise XMLSchemaValueError("{!r} has no schema bindings".format(self)) return encoder.encode(self, validation=validation, **kwargs) to_etree = encode def tostring(self, indent: str = '', max_lines: Optional[int] = None, spaces_for_tab: int = 4) -> Any: """Serializes the data element tree to an XML source string.""" root, errors = self.encode(validation='lax') return etree_tostring(root, self.nsmap, indent, max_lines, spaces_for_tab) def find(self, path: str, namespaces: Optional[NamespacesType] = None) -> Optional['DataElement']: """ Finds the first data element matching the path. :param path: an XPath expression that considers the data element as the root. :param namespaces: an optional mapping from namespace prefix to namespace URI. :return: the first matching data element or ``None`` if there is no match. """ parser = XPath2Parser(namespaces, strict=False) context = XPathContext(cast(Any, self)) result = next(parser.parse(path).select_results(context), None) return result if isinstance(result, DataElement) else None def findall(self, path: str, namespaces: Optional[NamespacesType] = None) -> List['DataElement']: """ Finds all data elements matching the path. :param path: an XPath expression that considers the data element as the root. :param namespaces: an optional mapping from namespace prefix to full name. :return: a list containing all matching data elements in document order, \ an empty list is returned if there is no match. """ parser = XPath2Parser(namespaces, strict=False) context = XPathContext(cast(Any, self)) results = parser.parse(path).get_results(context) if not isinstance(results, list): return [] return [e for e in results if isinstance(e, DataElement)] def iterfind(self, path: str, namespaces: Optional[NamespacesType] = None) -> Iterator['DataElement']: """ Creates and iterator for all XSD subelements matching the path. :param path: an XPath expression that considers the data element as the root. :param namespaces: is an optional mapping from namespace prefix to full name. :return: an iterable yielding all matching data elements in document order. """ parser = XPath2Parser(namespaces, strict=False) context = XPathContext(cast(Any, self)) results = parser.parse(path).select_results(context) yield from filter(lambda x: isinstance(x, DataElement), results) # type: ignore[misc] def iter(self, tag: Optional[str] = None) -> Iterator['DataElement']: """ Creates an iterator for the data element and its subelements. If tag is not `None` or '*', only data elements whose matches tag are returned from the iterator. """ if tag == '*': tag = None if tag is None or tag == self.tag: yield self for child in self._children: yield from child.iter(tag) def iterchildren(self, tag: Optional[str] = None) -> Iterator['DataElement']: """ Creates an iterator for the child data elements. If *tag* is not `None` or '*', only data elements whose name matches tag are returned from the iterator. """ if tag == '*': tag = None for child in self: if tag is None or tag == child.tag: yield child class DataBindingMeta(ABCMeta): """Metaclass for creating classes with bindings to XSD elements.""" xsd_element: 'XsdElement' def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], attrs: Dict[str, Any]) -> 'DataBindingMeta': try: xsd_element = attrs['xsd_element'] except KeyError: msg = "attribute 'xsd_element' is required for an XSD data binding class" raise XMLSchemaAttributeError(msg) from None if not isinstance(xsd_element, validators.XsdElement): raise XMLSchemaTypeError("{!r} is not an XSD element".format(xsd_element)) attrs['__module__'] = None return super(DataBindingMeta, mcs).__new__(mcs, name, bases, attrs) def __init__(cls, name: str, bases: Tuple[Type[Any], ...], attrs: Dict[str, Any]) -> None: super(DataBindingMeta, cls).__init__(name, bases, attrs) cls.xsd_version = cls.xsd_element.xsd_version cls.namespace = cls.xsd_element.target_namespace def fromsource(cls, source: Union[XMLSourceType, XMLResource], allow: str = 'all', defuse: str = 'remote', timeout: int = 300, **kwargs: Any) -> DecodeType[Any]: if not isinstance(source, XMLResource): source = XMLResource(source, allow=allow, defuse=defuse, timeout=timeout) if 'converter' not in kwargs: kwargs['converter'] = DataBindingConverter return cls.xsd_element.schema.decode(source, **kwargs) class DataElementConverter(XMLSchemaConverter): """ XML Schema based converter class for DataElement objects. :param namespaces: a dictionary map from namespace prefixes to URI. :param data_element_class: MutableSequence subclass to use for decoded data. \ Default is `DataElement`. """ __slots__ = 'data_element_class', def __init__(self, namespaces: Optional[NamespacesType] = None, data_element_class: Optional[Type['DataElement']] = None, **kwargs: Any) -> None: if data_element_class is None: self.data_element_class = DataElement else: self.data_element_class = data_element_class kwargs.update(attr_prefix='', text_key='', cdata_prefix='') super(DataElementConverter, self).__init__(namespaces, **kwargs) @property def lossy(self) -> bool: return False @property def losslessly(self) -> bool: return True def copy(self, **kwargs: Any) -> 'DataElementConverter': obj = cast(DataElementConverter, super().copy(**kwargs)) obj.data_element_class = kwargs.get('data_element_class', self.data_element_class) return obj def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> 'DataElement': data_element = self.data_element_class( tag=data.tag, value=data.text, nsmap=self.namespaces, xsd_element=xsd_element, xsd_type=xsd_type ) data_element.attrib.update((k, v) for k, v in self.map_attributes(data.attributes)) if (xsd_type or xsd_element.type).model_group is not None: for name, value, _ in self.map_content(data.content): if not name.isdigit(): data_element.append(value) else: try: data_element[-1].tail = value except IndexError: data_element.value = value return data_element def element_encode(self, data_element: 'DataElement', xsd_element: 'XsdElement', level: int = 0) -> ElementData: self.namespaces.update(data_element.nsmap) if not xsd_element.is_matching(data_element.tag, self._namespaces.get('')): raise XMLSchemaValueError("Unmatched tag") attributes = {self.unmap_qname(k, xsd_element.attributes): v for k, v in data_element.attrib.items()} data_len = len(data_element) if not data_len: return ElementData(data_element.tag, data_element.value, None, attributes) content: List[Tuple[Union[str, int], Any]] = [] cdata_num = count(1) if data_element.value is not None: content.append((next(cdata_num), data_element.value)) for e in data_element: content.append((e.tag, e)) if e.tail is not None: content.append((next(cdata_num), e.tail)) return ElementData(data_element.tag, None, content, attributes) class DataBindingConverter(DataElementConverter): """ A :class:`DataElementConverter` that uses XML data binding classes for decoding. Takes the same arguments of its parent class but the argument *data_element_class* is used for define the base for creating the missing XML binding classes. """ __slots__ = () def element_decode(self, data: ElementData, xsd_element: 'XsdElement', xsd_type: Optional[BaseXsdType] = None, level: int = 0) -> 'DataElement': cls = xsd_element.get_binding(self.data_element_class) data_element = cls( tag=data.tag, value=data.text, nsmap=self.namespaces, xsd_type=xsd_type ) data_element.attrib.update((k, v) for k, v in self.map_attributes(data.attributes)) if (xsd_type or xsd_element.type).model_group is not None: for name, value, _ in self.map_content(data.content): if not name.isdigit(): data_element.append(value) else: try: data_element[-1].tail = value except IndexError: data_element.value = value return data_element ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/documents.py�������������������������������������������������������������0000664�0000000�0000000�00000073003�14211403446�0020110�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import json from io import IOBase, TextIOBase from typing import Any, Dict, List, Optional, Type, Union, Tuple, \ IO, BinaryIO, TextIO, Iterator from .exceptions import XMLSchemaTypeError, XMLSchemaValueError, XMLResourceError from .names import XSD_NAMESPACE, XSI_TYPE from .etree import ElementTree, etree_tostring from .aliases import ElementType, XMLSourceType, NamespacesType, LocationsType, \ LazyType, SchemaSourceType, ConverterType, DecodeType, EncodeType, \ JsonDecodeType from .helpers import is_etree_document from .resources import fetch_schema_locations, XMLResource from .validators import XMLSchema10, XMLSchemaBase, XMLSchemaValidationError def get_context(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[Union[XMLSchemaBase, SchemaSourceType]] = None, cls: Optional[Type[XMLSchemaBase]] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False, dummy_schema: bool = False) -> Tuple[XMLResource, XMLSchemaBase]: """ Get the XML document validation/decode context. :return: an XMLResource instance and a schema instance. """ resource: XMLResource kwargs: Dict[Any, Any] if cls is None: cls = XMLSchema10 elif not issubclass(cls, XMLSchemaBase): raise XMLSchemaTypeError(f"invalid schema class {cls}") if isinstance(xml_document, XMLResource): resource = xml_document else: resource = XMLResource(xml_document, base_url, defuse=defuse, timeout=timeout, lazy=lazy) if isinstance(schema, XMLSchemaBase) and resource.namespace in schema.maps.namespaces: return resource, schema if isinstance(resource, XmlDocument) and isinstance(resource.schema, XMLSchemaBase): return resource, resource.schema try: schema_location, locations = fetch_schema_locations(resource, locations, base_url=base_url) except ValueError: if schema is None: if XSI_TYPE in resource.root.attrib and cls.meta_schema is not None: return resource, cls.meta_schema elif dummy_schema: return resource, get_dummy_schema(resource, cls) else: msg = "no schema can be retrieved for the provided XML data" raise XMLSchemaValueError(msg) from None elif isinstance(schema, XMLSchemaBase): return resource, schema else: return resource, cls(schema, locations=locations, base_url=base_url, defuse=defuse, timeout=timeout) else: kwargs = dict(locations=locations, defuse=defuse, timeout=timeout) if schema is None or isinstance(schema, XMLSchemaBase): return resource, cls(schema_location, **kwargs) else: return resource, cls(schema, **kwargs) def get_dummy_schema(resource: XMLResource, cls: Type[XMLSchemaBase]) -> XMLSchemaBase: tag = resource.root.tag if tag.startswith('{'): namespace, name = tag[1:].split('}') else: namespace, name = '', tag if namespace: return cls( '<xs:schema xmlns:xs="{0}" targetNamespace="{1}">\n' ' <xs:element name="{2}"/>\n' '</xs:schema>'.format(XSD_NAMESPACE, namespace, name) ) else: return cls( '<xs:schema xmlns:xs="{0}">\n' ' <xs:element name="{1}"/>\n' '</xs:schema>'.format(XSD_NAMESPACE, name) ) def get_lazy_json_encoder(errors: List[XMLSchemaValidationError]) -> Type[json.JSONEncoder]: class JSONLazyEncoder(json.JSONEncoder): def default(self, obj: Any) -> Any: if isinstance(obj, Iterator): while True: result = next(obj, None) if isinstance(result, XMLSchemaValidationError): errors.append(result) else: return result return json.JSONEncoder.default(self, obj) return JSONLazyEncoder def validate(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False) -> None: """ Validates an XML document against a schema instance. This function builds an :class:`XMLSchema` object for validating the XML document. Raises an :exc:`XMLSchemaValidationError` if the XML document is not validated against the schema. :param xml_document: can be an :class:`XMLResource` instance, a file-like object a path \ to a file or an URI of a resource or an Element instance or an ElementTree instance or \ a string containing the XML data. If the passed argument is not an :class:`XMLResource` \ instance a new one is built using this and *defuse*, *timeout* and *lazy* arguments. :param schema: can be a schema instance or a file-like object or a file path or a URL \ of a resource or a string containing the schema. :param cls: class to use for building the schema instance (for default \ :class:`XMLSchema10` is used). :param path: is an optional XPath expression that matches the elements of the XML \ data that have to be decoded. If not provided the XML root element is used. :param schema_path: an XPath expression to select the XSD element to use for decoding. \ If not provided the *path* argument or the *source* root tag are used. :param use_defaults: defines when to use element and attribute defaults for filling \ missing required values. :param namespaces: is an optional mapping from namespace prefix to URI. :param locations: additional schema location hints, used if a schema instance \ has to be built. :param base_url: is an optional custom base URL for remapping relative locations, for \ default uses the directory where the XSD or alternatively the XML document is located. :param defuse: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param timeout: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param lazy: optional argument for construct the :class:`XMLResource` instance. """ source, _schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) _schema.validate(source, path, schema_path, use_defaults, namespaces) def is_valid(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False) -> bool: """ Like :meth:`validate` except that do not raises an exception but returns ``True`` if the XML document is valid, ``False`` if it's invalid. """ source, schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) return schema.is_valid(source, path, schema_path, use_defaults, namespaces) def iter_errors(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False) -> Iterator[XMLSchemaValidationError]: """ Creates an iterator for the errors generated by the validation of an XML document. Takes the same arguments of the function :meth:`validate`. """ source, schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) return schema.iter_errors(source, path, schema_path, use_defaults, namespaces) def iter_decode(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, validation: str = 'strict', process_namespaces: bool = True, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False, **kwargs: Any) -> Iterator[Union[Any, XMLSchemaValidationError]]: """ Creates an iterator for decoding an XML source to a data structure. For default the document is validated during the decoding phase and if it's invalid then one or more :exc:`XMLSchemaValidationError` instances are yielded before the decoded data. :param xml_document: can be an :class:`XMLResource` instance, a file-like object a path \ to a file or an URI of a resource or an Element instance or an ElementTree instance or \ a string containing the XML data. If the passed argument is not an :class:`XMLResource` \ instance a new one is built using this and *defuse*, *timeout* and *lazy* arguments. :param schema: can be a schema instance or a file-like object or a file path or a URL \ of a resource or a string containing the schema. :param cls: class to use for building the schema instance (for default uses \ :class:`XMLSchema10`). :param path: is an optional XPath expression that matches the elements of the XML \ data that have to be decoded. If not provided the XML root element is used. :param validation: defines the XSD validation mode to use for decode, can be \ 'strict', 'lax' or 'skip'. :param process_namespaces: indicates whether to use namespace information in \ the decoding process. :param locations: additional schema location hints, in case a schema instance \ has to be built. :param base_url: is an optional custom base URL for remapping relative locations, for \ default uses the directory where the XSD or alternatively the XML document is located. :param defuse: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param timeout: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param lazy: optional argument for construct the :class:`XMLResource` instance. :param kwargs: other optional arguments of :meth:`XMLSchema.iter_decode` \ as keyword arguments. :raises: :exc:`XMLSchemaValidationError` if the XML document is invalid and \ ``validation='strict'`` is provided. """ source, _schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) yield from _schema.iter_decode(source, path=path, validation=validation, process_namespaces=process_namespaces, **kwargs) def to_dict(xml_document: Union[XMLSourceType, XMLResource], schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, validation: str = 'strict', process_namespaces: bool = True, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False, **kwargs: Any) -> DecodeType[Any]: """ Decodes an XML document to a Python's nested dictionary. Takes the same arguments of the function :meth:`iter_decode`, but *validation* mode defaults to 'strict'. :return: an object containing the decoded data. If ``validation='lax'`` is provided \ validation errors are collected and returned in a tuple with the decoded data. :raises: :exc:`XMLSchemaValidationError` if the XML document is invalid and \ ``validation='strict'`` is provided. """ source, _schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) return _schema.decode(source, path=path, validation=validation, process_namespaces=process_namespaces, **kwargs) def to_json(xml_document: Union[XMLSourceType, XMLResource], fp: Optional[IO[str]] = None, schema: Optional[XMLSchemaBase] = None, cls: Optional[Type[XMLSchemaBase]] = None, path: Optional[str] = None, converter: Optional[ConverterType] = None, process_namespaces: bool = True, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False, json_options: Optional[Dict[str, Any]] = None, **kwargs: Any) -> JsonDecodeType: """ Serialize an XML document to JSON. For default the XML data is validated during the decoding phase. Raises an :exc:`XMLSchemaValidationError` if the XML document is not validated against the schema. :param xml_document: can be an :class:`XMLResource` instance, a file-like object a path \ to a file or an URI of a resource or an Element instance or an ElementTree instance or \ a string containing the XML data. If the passed argument is not an :class:`XMLResource` \ instance a new one is built using this and *defuse*, *timeout* and *lazy* arguments. :param fp: can be a :meth:`write()` supporting file-like object. :param schema: can be a schema instance or a file-like object or a file path or an URL \ of a resource or a string containing the schema. :param cls: schema class to use for building the instance (for default uses \ :class:`XMLSchema10`). :param path: is an optional XPath expression that matches the elements of the XML \ data that have to be decoded. If not provided the XML root element is used. :param converter: an :class:`XMLSchemaConverter` subclass or instance to use \ for the decoding. :param process_namespaces: indicates whether to use namespace information in \ the decoding process. :param locations: additional schema location hints, in case the schema instance \ has to be built. :param base_url: is an optional custom base URL for remapping relative locations, for \ default uses the directory where the XSD or alternatively the XML document is located. :param defuse: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param timeout: optional argument to pass for construct schema and \ :class:`XMLResource` instances. :param lazy: optional argument for construct the :class:`XMLResource` instance. :param json_options: a dictionary with options for the JSON serializer. :param kwargs: optional arguments of :meth:`XMLSchema.iter_decode` as keyword arguments \ to variate the decoding process. :return: a string containing the JSON data if *fp* is `None`, otherwise doesn't \ return anything. If ``validation='lax'`` keyword argument is provided the validation \ errors are collected and returned, eventually coupled in a tuple with the JSON data. :raises: :exc:`XMLSchemaValidationError` if the object is not decodable by \ the XSD component, or also if it's invalid when ``validation='strict'`` is provided. """ source, _schema = get_context( xml_document, schema, cls, locations, base_url, defuse, timeout, lazy ) if json_options is None: json_options = {} if 'decimal_type' not in kwargs: kwargs['decimal_type'] = float kwargs['converter'] = converter kwargs['process_namespaces'] = process_namespaces errors: List[XMLSchemaValidationError] = [] if path is None and source.is_lazy() and 'cls' not in json_options: json_options['cls'] = get_lazy_json_encoder(errors) obj = _schema.decode(source, path=path, **kwargs) if isinstance(obj, tuple): errors.extend(obj[1]) if fp is not None: json.dump(obj[0], fp, **json_options) return tuple(errors) else: result = json.dumps(obj[0], **json_options) return result, tuple(errors) elif fp is not None: json.dump(obj, fp, **json_options) return None if not errors else tuple(errors) else: result = json.dumps(obj, **json_options) return result if not errors else (result, tuple(errors)) def from_json(source: Union[str, bytes, IO[str]], schema: XMLSchemaBase, path: Optional[str] = None, converter: Optional[ConverterType] = None, json_options: Optional[Dict[str, Any]] = None, **kwargs: Any) -> EncodeType[ElementType]: """ Deserialize JSON data to an XML Element. :param source: can be a string or a :meth:`read()` supporting file-like object \ containing the JSON document. :param schema: an :class:`XMLSchema10` or an :class:`XMLSchema11` instance. :param path: is an optional XPath expression for selecting the element of the schema \ that matches the data that has to be encoded. For default the first global element of \ the schema is used. :param converter: an :class:`XMLSchemaConverter` subclass or instance to use \ for the encoding. :param json_options: a dictionary with options for the JSON deserializer. :param kwargs: other optional arguments of :meth:`XMLSchema.iter_encode` and \ options for converter. :return: An element tree's Element instance. If ``validation='lax'`` keyword argument is \ provided the validation errors are collected and returned coupled in a tuple with the \ Element instance. :raises: :exc:`XMLSchemaValidationError` if the object is not encodable by the schema, \ or also if it's invalid when ``validation='strict'`` is provided. """ if not isinstance(schema, XMLSchemaBase): raise XMLSchemaTypeError("invalid type %r for argument 'schema'" % type(schema)) elif json_options is None: json_options = {} if isinstance(source, (str, bytes)): obj = json.loads(source, **json_options) else: obj = json.load(source, **json_options) return schema.encode(obj, path=path, converter=converter, **kwargs) class XmlDocument(XMLResource): """ An XML document bound with its schema. If no schema is get from the provided context and validation argument is 'skip' the XML document is associated with a generic schema, otherwise a ValueError is raised. :param source: a string containing XML data or a file path or an URL or a \ file like object or an ElementTree or an Element. :param schema: can be a :class:`xmlschema.XMLSchema` instance or a file-like \ object or a file path or an URL of a resource or a string containing the XSD schema. :param cls: class to use for building the schema instance (for default \ :class:`XMLSchema10` is used). :param validation: the XSD validation mode to use for validating the XML document, \ that can be 'strict' (default), 'lax' or 'skip'. :param namespaces: is an optional mapping from namespace prefix to URI. :param locations: resource location hints, that can be a dictionary or a \ sequence of couples (namespace URI, resource URL). :param base_url: the base URL for base :class:`xmlschema.XMLResource` initialization. :param allow: the security mode for base :class:`xmlschema.XMLResource` initialization. :param defuse: the defuse mode for base :class:`xmlschema.XMLResource` initialization. :param timeout: the timeout for base :class:`xmlschema.XMLResource` initialization. :param lazy: the lazy mode for base :class:`xmlschema.XMLResource` initialization. """ schema: Optional[XMLSchemaBase] = None _fallback_schema: Optional[XMLSchemaBase] = None validation: str = 'skip' namespaces: Optional[NamespacesType] = None errors: Union[Tuple[()], List[XMLSchemaValidationError]] = () def __init__(self, source: XMLSourceType, schema: Optional[Union[XMLSchemaBase, SchemaSourceType]] = None, cls: Optional[Type[XMLSchemaBase]] = None, validation: str = 'strict', namespaces: Optional[NamespacesType] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 300, lazy: LazyType = False) -> None: if cls is None: cls = XMLSchema10 self.validation = validation self._namespaces = namespaces super(XmlDocument, self).__init__(source, base_url, allow, defuse, timeout, lazy) if isinstance(schema, XMLSchemaBase) and self.namespace in schema.maps.namespaces: self.schema = schema elif schema is not None and not isinstance(schema, XMLSchemaBase): self.schema = cls( source=schema, base_url=base_url, allow=allow, defuse=defuse, timeout=timeout, ) else: try: schema_location, locations = fetch_schema_locations(self, locations, base_url) except ValueError: if XSI_TYPE in self._root.attrib: self.schema = cls.meta_schema elif validation != 'skip': msg = "no schema can be retrieved for the XML resource" raise XMLSchemaValueError(msg) from None else: self._fallback_schema = get_dummy_schema(self, cls) else: self.schema = cls( source=schema_location, validation='strict', locations=locations, defuse=defuse, allow=allow, timeout=timeout, ) if self.schema is None: pass elif validation == 'strict': self.schema.validate(self, namespaces=self.namespaces) elif validation == 'lax': self.errors = [e for e in self.schema.iter_errors(self, namespaces=self.namespaces)] elif validation != 'skip': raise XMLSchemaValueError("{!r}: not a validation mode".format(validation)) def parse(self, source: XMLSourceType, lazy: LazyType = False) -> None: super(XmlDocument, self).parse(source, lazy) self.namespaces = self.get_namespaces(self._namespaces) if self.schema is None: pass elif self.validation == 'strict': self.schema.validate(self, namespaces=self.namespaces) elif self.validation == 'lax': self.errors = [e for e in self.schema.iter_errors(self, namespaces=self.namespaces)] def getroot(self) -> ElementType: """Get the root element of the XML document.""" return self._root def get_etree_document(self) -> Any: """ The resource as ElementTree XML document. If the resource is lazy raises a resource error. """ if is_etree_document(self._source): return self._source elif self._lazy: msg = "cannot create an ElementTree from a lazy resource" raise XMLResourceError(msg) elif hasattr(self._root, 'nsmap'): return self._root.getroottree() # type: ignore[attr-defined] else: return ElementTree.ElementTree(self._root) def tostring(self, indent: str = '', max_lines: Optional[int] = None, spaces_for_tab: int = 4, xml_declaration: bool = False, encoding: str = 'unicode', method: str = 'xml') -> str: if self._lazy: raise XMLResourceError("cannot serialize a lazy XML document") _string = etree_tostring( elem=self._root, namespaces=self.namespaces, xml_declaration=xml_declaration, encoding=encoding, method=method ) if isinstance(_string, bytes): return _string.decode('utf-8') return _string def decode(self, **kwargs: Any) -> DecodeType[Any]: """ Decode the XML document to a nested Python dictionary. :param kwargs: options for the decode/to_dict method of the schema instance. """ if 'validation' not in kwargs: kwargs['validation'] = self.validation if 'namespaces' not in kwargs: kwargs['namespaces'] = self.namespaces schema = self.schema or self._fallback_schema if schema is None: return None obj = schema.to_dict(self, **kwargs) return obj[0] if isinstance(obj, tuple) else obj def to_json(self, fp: Optional[IO[str]] = None, json_options: Optional[Dict[str, Any]] = None, **kwargs: Any) -> JsonDecodeType: """ Converts loaded XML data to a JSON string or file. :param fp: can be a :meth:`write()` supporting file-like object. :param json_options: a dictionary with options for the JSON deserializer. :param kwargs: options for the decode/to_dict method of the schema instance. """ if json_options is None: json_options = {} path = kwargs.pop('path', None) if 'validation' not in kwargs: kwargs['validation'] = self.validation if 'namespaces' not in kwargs: kwargs['namespaces'] = self.namespaces if 'decimal_type' not in kwargs: kwargs['decimal_type'] = float errors: List[XMLSchemaValidationError] = [] if path is None and self._lazy and 'cls' not in json_options: json_options['cls'] = get_lazy_json_encoder(errors) kwargs['lazy_decode'] = True schema = self.schema or self._fallback_schema if schema is not None: obj = schema.decode(self, path=path, **kwargs) else: obj = None if isinstance(obj, tuple): if fp is not None: json.dump(obj[0], fp, **json_options) obj[1].extend(errors) return tuple(obj[1]) else: result = json.dumps(obj[0], **json_options) obj[1].extend(errors) return result, tuple(obj[1]) elif fp is not None: json.dump(obj, fp, **json_options) return None if not errors else tuple(errors) else: result = json.dumps(obj, **json_options) return result if not errors else (result, tuple(errors)) def write(self, file: Union[str, TextIO, BinaryIO], encoding: str = 'us-ascii', xml_declaration: bool = False, default_namespace: Optional[str] = None, method: str = "xml") -> None: """Serialize an XML resource to a file. Cannot be used with lazy resources.""" if self._lazy: raise XMLResourceError("cannot serialize a lazy XML document") kwargs: Dict[str, Any] = { 'xml_declaration': xml_declaration, 'encoding': encoding, 'method': method, } if not default_namespace: kwargs['namespaces'] = self.namespaces else: namespaces: Optional[Dict[Optional[str], str]] if self.namespaces is None: namespaces = {} else: namespaces = {k: v for k, v in self.namespaces.items()} if hasattr(self._root, 'nsmap'): # noinspection PyTypeChecker namespaces[None] = default_namespace else: namespaces[''] = default_namespace kwargs['namespaces'] = namespaces _string = etree_tostring(self._root, **kwargs) if isinstance(file, str): if isinstance(_string, str): with open(file, 'w', encoding='utf-8') as fp: fp.write(_string) else: with open(file, 'wb') as _fp: _fp.write(_string) elif isinstance(file, TextIOBase): if isinstance(_string, bytes): file.write(_string.decode('utf-8')) else: file.write(_string) elif isinstance(file, IOBase): if isinstance(_string, str): file.write(_string.encode('utf-8')) else: file.write(_string) else: raise XMLSchemaTypeError(f"unexpected type {type(file)} for 'file' argument") �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/etree.py�����������������������������������������������������������������0000664�0000000�0000000�00000021407�14211403446�0017214�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ A unified setup module for ElementTree with a safe parser and helper functions. """ import sys import re from collections import namedtuple from typing import Any, MutableMapping, Optional, Union from .exceptions import XMLSchemaTypeError _REGEX_NS_PREFIX = re.compile(r'ns\d+$') ### # Programmatic import of xml.etree.ElementTree # # In Python 3 the pure python implementation is overwritten by the C module API, # so use a programmatic re-import to obtain the pure Python module, necessary for # defining a safer XMLParser. # if '_elementtree' in sys.modules: if 'xml.etree.ElementTree' not in sys.modules: raise RuntimeError("Inconsistent status for ElementTree module: module " "is missing but the C optimized version is imported.") import xml.etree.ElementTree as ElementTree # Temporary remove the loaded modules sys.modules.pop('xml.etree.ElementTree') _cmod = sys.modules.pop('_elementtree') # Load the pure Python module sys.modules['_elementtree'] = None # type: ignore[assignment] import xml.etree.ElementTree as PyElementTree import xml.etree # Restore original modules sys.modules['_elementtree'] = _cmod xml.etree.ElementTree = ElementTree sys.modules['xml.etree.ElementTree'] = ElementTree else: # Load the pure Python module sys.modules['_elementtree'] = None # type: ignore[assignment] import xml.etree.ElementTree as PyElementTree # Remove the pure Python module from imported modules del sys.modules['xml.etree'] del sys.modules['xml.etree.ElementTree'] del sys.modules['_elementtree'] # Load the C optimized ElementTree module import xml.etree.ElementTree as ElementTree etree_element = ElementTree.Element ParseError = ElementTree.ParseError py_etree_element = PyElementTree.Element class SafeXMLParser(PyElementTree.XMLParser): """ An XMLParser that forbids entities processing. Drops the *html* argument that is deprecated since version 3.4. :param target: the target object called by the `feed()` method of the \ parser, that defaults to `TreeBuilder`. :param encoding: if provided, its value overrides the encoding specified \ in the XML file. """ def __init__(self, target: Optional[Any] = None, encoding: Optional[str] = None) -> None: super(SafeXMLParser, self).__init__(target=target, encoding=encoding) self.parser.EntityDeclHandler = self.entity_declaration self.parser.UnparsedEntityDeclHandler = self.unparsed_entity_declaration self.parser.ExternalEntityRefHandler = self.external_entity_reference def entity_declaration(self, entity_name, is_parameter_entity, value, base, # type: ignore system_id, public_id, notation_name): raise PyElementTree.ParseError( "Entities are forbidden (entity_name={!r})".format(entity_name) ) def unparsed_entity_declaration(self, entity_name, base, system_id, # type: ignore public_id, notation_name): raise PyElementTree.ParseError( "Unparsed entities are forbidden (entity_name={!r})".format(entity_name) ) def external_entity_reference(self, context, base, system_id, public_id): # type: ignore raise PyElementTree.ParseError( "External references are forbidden (system_id={!r}, " "public_id={!r})".format(system_id, public_id) ) # pragma: no cover (EntityDeclHandler is called before) ElementData = namedtuple('ElementData', ['tag', 'text', 'content', 'attributes']) """ Namedtuple for Element data interchange between decoders and converters. The field *tag* is a string containing the Element's tag, *text* can be `None` or a string representing the Element's text, *content* can be `None`, a list containing the Element's children or a dictionary containing element name to list of element contents for the Element's children (used for unordered input data), *attributes* can be `None` or a dictionary containing the Element's attributes. """ def is_etree_element(obj: Any) -> bool: """A checker for valid ElementTree elements that excludes XsdElement objects.""" return hasattr(obj, 'append') and hasattr(obj, 'tag') and hasattr(obj, 'attrib') def etree_tostring(elem: etree_element, namespaces: Optional[MutableMapping[str, str]] = None, indent: str = '', max_lines: Optional[int] = None, spaces_for_tab: Optional[int] = None, xml_declaration: Optional[bool] = None, encoding: str = 'unicode', method: str = 'xml') -> Union[str, bytes]: """ Serialize an Element tree to a string. Tab characters are replaced by whitespaces. :param elem: the Element instance. :param namespaces: is an optional mapping from namespace prefix to URI. \ Provided namespaces are registered before serialization. :param indent: the base line indentation. :param max_lines: if truncate serialization after a number of lines \ (default: do not truncate). :param spaces_for_tab: number of spaces for replacing tab characters. \ For default tabs are replaced with 4 spaces, but only if not empty \ indentation or a max lines limit are provided. :param xml_declaration: if set to `True` inserts the XML declaration at the head. :param encoding: if "unicode" (the default) the output is a string, otherwise it’s binary. :param method: is either "xml" (the default), "html" or "text". :return: a Unicode string. """ def reindent(line: str) -> str: if not line: return line elif line.startswith(min_indent): return line[start:] if start >= 0 else indent[start:] + line else: return indent + line etree_module: Any if not is_etree_element(elem): raise XMLSchemaTypeError("{!r} is not an Element".format(elem)) elif isinstance(elem, py_etree_element): etree_module = PyElementTree elif not hasattr(elem, 'nsmap'): etree_module = ElementTree else: import lxml.etree as etree_module # type: ignore[no-redef] if namespaces: default_namespace = namespaces.get('') for prefix, uri in namespaces.items(): if prefix and not _REGEX_NS_PREFIX.match(prefix): etree_module.register_namespace(prefix, uri) if uri == default_namespace: default_namespace = None if default_namespace and not hasattr(elem, 'nsmap'): etree_module.register_namespace('', default_namespace) xml_text = etree_module.tostring(elem, encoding=encoding, method=method) if isinstance(xml_text, bytes): xml_text = xml_text.decode('utf-8') if spaces_for_tab: xml_text = xml_text.replace('\t', ' ' * spaces_for_tab) elif method != 'text' and (indent or max_lines): xml_text = xml_text.replace('\t', ' ' * 4) if xml_text.startswith('<?xml '): if xml_declaration is False: lines = xml_text.splitlines()[1:] else: lines = xml_text.splitlines() elif xml_declaration and encoding.lower() != 'unicode': lines = ['<?xml version="1.0" encoding="{}"?>'.format(encoding)] lines.extend(xml_text.splitlines()) else: lines = xml_text.splitlines() # Clear ending empty lines while lines and not lines[-1].strip(): lines.pop(-1) if not lines or method == 'text' or (not indent and not max_lines): if encoding == 'unicode': return '\n'.join(lines) return '\n'.join(lines).encode(encoding) last_indent = ' ' * min(k for k in range(len(lines[-1])) if lines[-1][k] != ' ') if len(lines) > 2: child_indent = ' ' * min( k for line in lines[1:-1] for k in range(len(line)) if line[k] != ' ' ) min_indent = min(child_indent, last_indent) else: min_indent = child_indent = last_indent start = len(min_indent) - len(indent) if max_lines is not None and len(lines) > max_lines + 2: lines = lines[:max_lines] + [child_indent + '...'] * 2 + lines[-1:] if encoding == 'unicode': return '\n'.join(reindent(line) for line in lines) return '\n'.join(reindent(line) for line in lines).encode(encoding) __all__ = ['ElementTree', 'PyElementTree', 'ParseError', 'SafeXMLParser', 'etree_element', 'py_etree_element', 'ElementData', 'is_etree_element', 'etree_tostring'] ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/exceptions.py������������������������������������������������������������0000664�0000000�0000000�00000002323�14211403446�0020265�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # class XMLSchemaException(Exception): """The base exception that let you catch all the errors generated by the library.""" class XMLSchemaOSError(XMLSchemaException, OSError): pass class XMLSchemaAttributeError(XMLSchemaException, AttributeError): pass class XMLSchemaTypeError(XMLSchemaException, TypeError): pass class XMLSchemaValueError(XMLSchemaException, ValueError): pass class XMLSchemaKeyError(XMLSchemaException, KeyError): pass class XMLSchemaRuntimeError(XMLSchemaException, RuntimeError): pass class XMLResourceError(XMLSchemaException, OSError): """Raised when an error is found accessing an XML resource.""" class XMLSchemaNamespaceError(XMLSchemaException, RuntimeError): """Raised when a wrong runtime condition is found with a namespace.""" class XMLSchemaWarning(Warning): """Base warning class for the XMLSchema package.""" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/������������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017040�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/__init__.py�������������������������������������������������������0000664�0000000�0000000�00000000000�14211403446�0021137�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/codegen.py��������������������������������������������������������0000664�0000000�0000000�00000052322�14211403446�0021022�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """ This module contains abstact base class and helper functions for building XSD based code generators. """ import os import re import sys import inspect import logging from abc import ABC, ABCMeta from fnmatch import fnmatch from pathlib import Path from typing import Optional, List from jinja2 import Environment, ChoiceLoader, FileSystemLoader, \ TemplateNotFound, TemplateAssertionError from elementpath import datatypes import xmlschema from xmlschema.validators import XsdType, XsdElement, XsdAttribute from xmlschema.names import XSD_NAMESPACE NCNAME_PATTERN = re.compile(r'^[^\d\W][\w.\-]*$') QNAME_PATTERN = re.compile( r'^(?:(?P<prefix>[^\d\W][\w\-.\xb7\u0387\u06DD\u06DE]*):)?' r'(?P<local>[^\d\W][\w\-.\xb7\u0387\u06DD\u06DE]*)$', ) def is_shell_wildcard(pathname): return '*' in pathname or '?' in pathname or '[' in pathname def xsd_qname(name): return '{%s}%s' % (XSD_NAMESPACE, name) def filter_method(func): """Marks a method for registration as template filter.""" func.is_filter = True return func def test_method(func): """Marks a method for registration as template test.""" func.is_test = True return func logger = logging.getLogger('xmlschema-codegen') class GeneratorMeta(ABCMeta): """Metaclass for creating code generators. Checks formal_language """ def __new__(mcs, name, bases, attrs): module = sys.modules.get(attrs['__module__']) module_path = getattr(module, '__file__', os.getcwd()) formal_language = None searchpaths = [] builtin_types = {} for base in bases: if getattr(base, 'formal_language', None): if formal_language is None: formal_language = base.formal_language elif formal_language != base.formal_language: raise ValueError("ambiguous formal_language from base classes") if getattr(base, 'searchpaths', None): searchpaths.extend(base.searchpaths) if getattr(base, 'builtin_types', None): builtin_types.update(base.builtin_types) if 'formal_language' not in attrs: attrs['formal_language'] = formal_language elif formal_language and formal_language != attrs['formal_language']: raise ValueError("formal_language cannot be changed") try: for path in attrs['searchpaths']: if Path(path).is_absolute(): dirpath = Path(path) else: dirpath = Path(module_path).parent.joinpath(path) if not dirpath.is_dir(): raise ValueError("path {!r} is not a directory!".format(str(path))) searchpaths.append(dirpath) except (KeyError, TypeError): pass else: attrs['searchpaths'] = searchpaths try: for k, v in attrs['builtin_types'].items(): builtin_types[xsd_qname(k)] = v except (KeyError, AttributeError): pass finally: attrs['builtin_types'] = builtin_types return type.__new__(mcs, name, bases, attrs) class AbstractGenerator(ABC, metaclass=GeneratorMeta): """ Abstract base class for code generators based on Jinja2 template engine. :param schema: the source or the instance of the XSD schema. :param searchpath: additional search path for custom templates. \ If provided the search path has priority over searchpaths defined \ in generator class. :param types_map: a dictionary with custom mapping for XSD types. """ formal_language: Optional[str] = None """The formal language associated to the code generator (eg. Python).""" searchpaths: Optional[List[str]] = None """ Directory paths for searching templates, specified with a list or a tuple. Each path must be provided as relative from the directory of the module where the class is defined. Extends the searchpath defined in base classes. """ builtin_types = { 'anyType': '', 'anySimpleType': '', } """ Translation map for XSD builtin types. Updates the builtin_types defined in base classes. """ def __init__(self, schema, searchpath=None, types_map=None): if isinstance(schema, xmlschema.XMLSchemaBase): self.schema = schema else: self.schema = xmlschema.XMLSchema11(schema) file_loaders = [] if searchpath: file_loaders.append(FileSystemLoader(searchpath)) if self.searchpaths: file_loaders.extend( FileSystemLoader(str(path)) for path in reversed(self.searchpaths) ) if not file_loaders: raise ValueError("no search paths defined!") loader = ChoiceLoader(file_loaders) if len(file_loaders) > 1 else file_loaders[0] self.types_map = self.builtin_types.copy() if types_map: if not self.schema.target_namespace: self.types_map.update(types_map) else: ns_part = '{%s}' % self.schema.target_namespace self.types_map.update((ns_part + k, v) for k, v in types_map.items()) self.filters = {} self.tests = {} for name in filter(lambda x: callable(getattr(self, x)), dir(self)): method = getattr(self, name) if inspect.isfunction(method): # static methods if getattr(method, 'is_filter', False): self.filters[name] = method elif getattr(method, 'is_test', False): self.tests[name] = method elif inspect.isroutine(method) and hasattr(method, '__func__'): # class and instance methods if getattr(method.__func__, 'is_filter', False): self.filters[name] = method elif getattr(method.__func__, 'is_test', False): self.tests[name] = method type_mapping_filter = '{}_type'.format(self.formal_language).lower().replace(' ', '_') if type_mapping_filter not in self.filters: self.filters[type_mapping_filter] = self.map_type self._env = Environment(loader=loader) self._env.filters.update(self.filters) self._env.tests.update(self.tests) def __repr__(self): if self.schema.url: return '%s(schema=%r)' % (self.__class__.__name__, self.schema.name) return '%s(namespace=%r)' % (self.__class__.__name__, self.schema.target_namespace) def list_templates(self, extensions=None, filter_func=None): return self._env.list_templates(extensions, filter_func) def matching_templates(self, name): return self._env.list_templates(filter_func=lambda x: fnmatch(x, name)) def get_template(self, name, parent=None, global_vars=None): return self._env.get_template(name, parent, global_vars) def select_template(self, names, parent=None, global_vars=None): return self._env.select_template(names, parent, global_vars) def render(self, names, parent=None, global_vars=None): if isinstance(names, str): names = [names] elif not all(isinstance(x, str) for x in names): raise TypeError("'names' argument must contain only strings!") results = [] for name in names: try: template = self._env.get_template(name, parent, global_vars) except TemplateNotFound as err: logger.debug("name %r: %s", name, str(err)) except TemplateAssertionError as err: logger.warning("template %r: %s", name, str(err)) else: results.append(template.render(schema=self.schema)) return results def render_to_files(self, names, parent=None, global_vars=None, output_dir='.', force=False): if isinstance(names, str): names = [names] elif not all(isinstance(x, str) for x in names): raise TypeError("'names' argument must contain only strings!") template_names = [] for name in names: if is_shell_wildcard(name): template_names.extend(self.matching_templates(name)) else: template_names.append(name) output_dir = Path(output_dir) rendered = [] for name in template_names: try: template = self._env.get_template(name, parent, global_vars) except TemplateNotFound as err: logger.debug("name %r: %s", name, str(err)) except TemplateAssertionError as err: logger.warning("template %r: %s", name, str(err)) else: output_file = output_dir.joinpath(Path(name).name).with_suffix('') if not force and output_file.exists(): continue result = template.render(schema=self.schema) logger.info("write file %r", str(output_file)) with open(output_file, 'w') as fp: fp.write(result) rendered.append(str(output_file)) return rendered def map_type(self, obj): """ Maps an XSD type to a type declaration of the target language. This method is registered as filter with a name dependant from the language name (eg. c_type). :param obj: an XSD type or another type-related declaration as \ an attribute or an element. :return: an empty string for non-XSD objects. """ if isinstance(obj, XsdType): xsd_type = obj elif isinstance(obj, (XsdAttribute, XsdElement)): xsd_type = obj.type else: return '' try: return self.types_map[xsd_type.name] except KeyError: try: return self.types_map[xsd_type.base_type.name] except (KeyError, AttributeError): if xsd_type.is_complex(): return self.types_map[xsd_qname('anyType')] else: return self.types_map[xsd_qname('anySimpleType')] @staticmethod @filter_method def name(obj, unnamed='none'): """ Get the unqualified name of the provided object. Invalid chars for identifiers are replaced by an underscore. :param obj: an XSD object or a named object or a string. :param unnamed: value for unnamed objects. Defaults to 'none'. :return: str """ try: name = obj.local_name except AttributeError: try: obj = obj.name except AttributeError: pass if not isinstance(obj, str): return unnamed try: if obj[0] == '{': _, name = obj.split('}') elif ':' in obj: prefix, name = obj.split(':') if NCNAME_PATTERN.match(prefix) is None: return '' else: name = obj except (IndexError, ValueError): return '' else: if not isinstance(name, str): return '' if NCNAME_PATTERN.match(name) is None: return unnamed return name.replace('.', '_').replace('-', '_') @filter_method def qname(self, obj, unnamed='none', sep='__'): """ Get the QName of the provided object. Invalid chars for identifiers are replaced by an underscore. :param obj: an XSD object or a named object or a string. :param unnamed: value for unnamed objects. Defaults to 'none'. :param sep: the replacement for colon. Defaults to double underscore. :return: str """ try: qname = obj.prefixed_name except AttributeError: try: obj = obj.name except AttributeError: pass if not isinstance(obj, str): return unnamed try: if obj[0] == '{': namespace, local_name = obj[1:].split('}') for prefix, uri in self.schema.namespaces.items(): if uri == namespace: qname = '%s:%s' % (prefix, local_name) break else: qname = local_name else: qname = obj except IndexError: return '' except ValueError: return unnamed if not qname or QNAME_PATTERN.match(qname) is None: return unnamed return qname.replace('.', '_').replace('-', '_').replace(':', sep) @filter_method def namespace(self, obj): """Get the namespace URI of the provided object.""" try: namespace = obj.target_namespace except AttributeError: if isinstance(obj, datatypes.QName): return obj.namespace elif not isinstance(obj, str): return '' try: if obj[0] == '{': namespace, _ = obj[1:].split('}') return namespace elif ':' in obj: prefix, _ = obj.split(':') return self.schema.namespaces.get(prefix, '') else: return '' except (IndexError, ValueError): return '' else: return namespace if isinstance(namespace, str) else '' @staticmethod @filter_method def type_name(obj, suffix=None, unnamed='none'): """ Get the unqualified name of the XSD type. Invalid chars for identifiers are replaced by an underscore. :param obj: an instance of (XsdType|XsdAttribute|XsdElement). :param suffix: force a suffix. For default removes '_type' or 'Type' suffixes. :param unnamed: value for unnamed XSD types. Defaults to 'none'. :return: str """ if isinstance(obj, XsdType): name = obj.local_name or unnamed elif isinstance(obj, (XsdElement, XsdAttribute)): name = obj.type.local_name or unnamed else: name = unnamed if name.endswith('Type'): name = name[:-4] elif name.endswith('_type'): name = name[:-5] if suffix: name = '{}{}'.format(name, suffix) return name.replace('.', '_').replace('-', '_') @staticmethod @filter_method def type_qname(obj, suffix=None, unnamed='none', sep='__'): """ Get the unqualified name of the XSD type. Invalid chars for identifiers are replaced by an underscore. :param obj: an instance of (XsdType|XsdAttribute|XsdElement). :param suffix: force a suffix. For default removes '_type' or 'Type' suffixes. :param unnamed: value for unnamed XSD types. Defaults to 'none'. :param sep: the replacement for colon. Defaults to double underscore. :return: str """ if isinstance(obj, XsdType): qname = obj.prefixed_name or unnamed elif isinstance(obj, (XsdElement, XsdAttribute)): qname = obj.type.prefixed_name or unnamed else: qname = unnamed if qname.endswith('Type'): qname = qname[:-4] elif qname.endswith('_type'): qname = qname[:-5] if suffix: qname = '{}{}'.format(qname, suffix) return qname.replace('.', '_').replace('-', '_').replace(':', sep) @staticmethod @filter_method def sort_types(xsd_types, accept_circularity=False): """ Returns a sorted sequence of XSD types usable for building type declarations. :param xsd_types: a sequence with XSD types. :param accept_circularity: if set to `True` circularities \ are accepted. Defaults to `False`. :return: a list with ordered types. """ if not isinstance(xsd_types, (list, tuple)): try: xsd_types = list(xsd_types.values()) except AttributeError: pass assert all(isinstance(x, XsdType) for x in xsd_types) ordered_types = [x for x in xsd_types if x.is_simple()] ordered_types.extend(x for x in xsd_types if x.is_complex() and x.has_simple_content()) unordered = {x: [] for x in xsd_types if x.is_complex() and not x.has_simple_content()} for xsd_type in unordered: for e in xsd_type.content.iter_elements(): if e.type in unordered: unordered[xsd_type].append(e.type) while unordered: deleted = 0 for xsd_type in xsd_types: if xsd_type in unordered: if not unordered[xsd_type]: del unordered[xsd_type] ordered_types.append(xsd_type) deleted += 1 for xsd_type in unordered: unordered[xsd_type] = [x for x in unordered[xsd_type] if x in unordered] if not deleted: if not accept_circularity: raise ValueError("circularity found between {!r}".format(list(unordered))) ordered_types.extend(list(unordered)) break assert len(xsd_types) == len(ordered_types) return ordered_types def is_derived(self, xsd_type, *names, derivation=None): """ Returns `True` if the argument XSD type is derived from any of other types expressed by name, otherwise returns `False`. :param xsd_type: an XsdComplexType/XsdSimpleType instance. :param names: positional argument with the names of other \ XSD types. :param derivation: the type of derivation, that can be \ *extension* or *restriction*, or both with a space separator. \ If no value is provided it only checks if it is derived from \ or if it is the XSD type itself. """ for type_name in names: if not isinstance(type_name, str) or not type_name: continue # pragma: no cover elif type_name[0] != '{' and ':' in type_name: try: type_name = self.schema.resolve_qname(type_name) except xmlschema.XMLSchemaException: continue try: if xsd_type.is_derived(self.schema.maps.types[type_name], derivation): return True except KeyError: pass return False @test_method def derivation(self, xsd_type, *names): return self.is_derived(xsd_type, *names) @test_method def extension(self, xsd_type, *names): return self.is_derived(xsd_type, *names, derivation='extension') @test_method def restriction(self, xsd_type, *names): return self.is_derived(xsd_type, *names, derivation='restriction') @staticmethod @test_method def multi_sequence(xsd_type): try: return any(e.is_multiple() for e in xsd_type.content.iter_elements()) except AttributeError: return False class PythonGenerator(AbstractGenerator): """A Python code generator for XSD schemas.""" formal_language = 'Python' searchpaths = ['templates/python/'] builtin_types = { 'string': 'str', 'decimal': 'decimal.Decimal', 'float': 'float', 'double': 'float', 'date': 'datatypes.Date10', 'dateTime': 'datatypes.DateTime10', 'gDay': 'datatypes.GregorianDay', 'gMonth': 'datatypes.GregorianMonth', 'gMonthDay': 'datatypes.GregorianMonthDay', 'gYear': 'datatypes.GregorianYear10', 'gYearMonth': 'datatypes.GregorianYearMonth10', 'time': 'datatypes.Time', 'duration': 'datatypes.Duration', 'QName': 'datatypes.QName', 'NOTATION': 'datatypes.DateTime10', 'anyURI': 'datatypes.AnyURI', 'boolean': 'bool', 'base64Binary': 'datatypes.Base64Binary', 'hexBinary': 'datatypes.HexBinary', 'normalizedString': 'str', 'token': 'str', 'language': 'str', 'Name': 'str', 'NCName': 'str', 'ID': 'str', 'IDREF': 'str', 'ENTITY': 'str', 'NMTOKEN': 'str', 'integer': 'int', 'long': 'int', 'int': 'int', 'short': 'int', 'byte': 'int', 'nonNegativeInteger': 'int', 'positiveInteger': 'int', 'unsignedLong': 'int', 'unsignedInt': 'int', 'unsignedShort': 'int', 'unsignedByte': 'int', 'nonPositiveInteger': 'int', 'negativeInteger': 'int', # XSD 1.1 built-in types 'dateTimeStamp': 'datatypes.DateTimeStamp10', 'dayTimeDuration': 'datatypes.DayTimeDuration', 'yearMonthDuration': 'datatypes.YearMonthDuration', } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/templates/��������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0021036�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/templates/python/�������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0022357�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/templates/python/bindings.py.jinja��������������������������������0000664�0000000�0000000�00000001744�14211403446�0025626�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # Auto-generated code: don't edit this file # """ Sample of XML data bindings for schema {{ schema.name }} """ import xmlschema from xmlschema.dataobjects import DataElement, DataBindingMeta {% if schema.target_namespace -%} __NAMESPACE__ = "{{ schema.target_namespace }}" {%- endif %} {% if schema.XSD_VERSION == '1.0' -%} schema = xmlschema.XMLSchema10("{{ schema.name }}") {%- else -%} schema = xmlschema.XMLSchema11("{{ schema.name }}") {%- endif %} {# Bindings for global elements #} {%- for xsd_element in schema.elements.values() %} class {{ xsd_element|name|capitalize }}Binding(DataElement, metaclass=DataBindingMeta): xsd_element = schema.elements['{{ xsd_element.local_name }}'] {% endfor %}����������������������������xmlschema-1.10.0/xmlschema/extras/templates/python/sample.py.jinja����������������������������������0000664�0000000�0000000�00000002134�14211403446�0025304�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # Auto-generated code: don't edit this file # """ Sample of XSD generated code using test PythonGenerator class. """ import xmlschema {% if schema.target_namespace -%} __NAMESPACE__ = "{{ schema.target_namespace }}" {%- endif %} # # Schema types # {#- Render global types #} {% for xsd_type in ( schema.types.values()|sort_types ) %} class {{ xsd_type|name }}: content_type = '{{ xsd_type.content_type_label }}' {% endfor %} # # Schema elements # {#- Render global elements #} {% for xsd_element in schema.elements.values() %} class {{ xsd_element|name|capitalize }}: {% if xsd_element.type.is_global() -%} xsd_type = {{ xsd_element.type|name }} {%- elif xsd_element.type.is_simple() -%} xsd_type = {{ xsd_element.primitive_type|name }} {%- else %} pass {%- endif %} {% endfor %}������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/extras/wsdl.py�����������������������������������������������������������0000664�0000000�0000000�00000056360�14211403446�0020375�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore import os from ..exceptions import XMLSchemaException, XMLSchemaValueError from ..names import XSD_NAMESPACE, WSDL_NAMESPACE, SOAP_NAMESPACE, \ SCHEMAS_DIR, XSD_ANY_TYPE, XSD_SCHEMA from ..helpers import get_qname, local_name, get_extended_qname, get_prefixed_qname from ..namespaces import NamespaceResourcesMap from ..resources import fetch_resource from ..documents import XmlDocument from ..validators import XMLSchema10 # WSDL 1.1 global declarations WSDL_IMPORT = '{%s}import' % WSDL_NAMESPACE WSDL_TYPES = '{%s}types' % WSDL_NAMESPACE WSDL_MESSAGE = '{%s}message' % WSDL_NAMESPACE WSDL_PORT_TYPE = '{%s}portType' % WSDL_NAMESPACE WSDL_BINDING = '{%s}binding' % WSDL_NAMESPACE WSDL_SERVICE = '{%s}service' % WSDL_NAMESPACE # Other WSDL tags WSDL_PART = '{%s}part' % WSDL_NAMESPACE WSDL_PORT = '{%s}port' % WSDL_NAMESPACE WSDL_INPUT = '{%s}input' % WSDL_NAMESPACE WSDL_OUTPUT = '{%s}output' % WSDL_NAMESPACE WSDL_FAULT = '{%s}fault' % WSDL_NAMESPACE WSDL_OPERATION = '{%s}operation' % WSDL_NAMESPACE # WSDL SOAP Extensions SOAP_BINDING = '{%s}binding' % SOAP_NAMESPACE SOAP_OPERATION = '{%s}operation' % SOAP_NAMESPACE SOAP_BODY = '{%s}body' % SOAP_NAMESPACE SOAP_FAULT = '{%s}fault' % SOAP_NAMESPACE SOAP_HEADER = '{%s}header' % SOAP_NAMESPACE SOAP_HEADERFAULT = '{%s}headerfault' % SOAP_NAMESPACE SOAP_ADDRESS = '{%s}address' % SOAP_NAMESPACE class WsdlParseError(XMLSchemaException, SyntaxError): """An error during parsing of a WSDL document.""" class Wsdl11Maps: def __init__(self, wsdl_document): self.wsdl_document = wsdl_document self.imports = {} self.messages = {} self.port_types = {} self.bindings = {} self.services = {} def clear(self): self.imports.clear() self.messages.clear() self.port_types.clear() self.bindings.clear() self.services.clear() class WsdlComponent: def __init__(self, elem, wsdl_document): self.elem = elem self.wsdl_document = wsdl_document self.name = get_qname(wsdl_document.target_namespace, elem.get('name')) def __repr__(self): return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) def get(self, name): return self.elem.get(name) @property def attrib(self): return self.elem.attrib @property def local_name(self): if self.name: return local_name(self.name) @property def prefixed_name(self): if self.name: return get_prefixed_qname(self.name, self.wsdl_document.namespaces) def map_qname(self, qname): return get_prefixed_qname(qname, self.wsdl_document.namespaces) def unmap_qname(self, qname): return get_extended_qname(qname, self.wsdl_document.namespaces) def _parse_reference(self, elem, attribute_name): try: return self.unmap_qname(elem.attrib[attribute_name]) except KeyError: return # a missing attribute is already caught by XSD validator class WsdlMessage(WsdlComponent): def __init__(self, elem, wsdl_document): super(WsdlMessage, self).__init__(elem, wsdl_document) self.parts = {} xsd_elements = wsdl_document.schema.maps.elements xsd_types = wsdl_document.schema.maps.types for child in elem.iterfind(WSDL_PART): part_name = child.get('name') if part_name is None: continue # Ignore, missing name is already caught by XSD validator elif part_name in self.parts: msg = "duplicated part {!r} for {!r}" wsdl_document.parse_error(msg.format(part_name, self)) try: element_attr = child.attrib['element'] except KeyError: pass else: if 'type' in child.attrib: msg = "ambiguous binding with both 'type' and 'element' attributes" wsdl_document.parse_error(msg) element_name = get_extended_qname(element_attr, wsdl_document.namespaces) try: self.parts[part_name] = xsd_elements[element_name] except KeyError: self.parts[part_name] = xsd_types[XSD_ANY_TYPE] msg = "missing schema element {!r}".format(element_name) wsdl_document.parse_error(msg) continue # pragma: no cover try: type_attr = child.attrib['type'] except KeyError: msg = "missing both 'type' and 'element' attributes" wsdl_document.parse_error(msg) else: type_name = get_extended_qname(type_attr, wsdl_document.namespaces) try: self.parts[part_name] = xsd_types[type_name] except KeyError: self.parts[part_name] = xsd_types[XSD_ANY_TYPE] msg = "missing schema type {!r}".format(type_name) wsdl_document.parse_error(msg) class WsdlPortType(WsdlComponent): def __init__(self, elem, wsdl_document): super(WsdlPortType, self).__init__(elem, wsdl_document) self.operations = {} for child in elem.iterfind(WSDL_OPERATION): operation_name = child.get('name') if operation_name is None: continue # Ignore, missing name is already caught by XSD validator operation = WsdlOperation(child, wsdl_document) key = operation.key if key in self.operations: msg = "duplicated operation {!r} for {!r}" wsdl_document.parse_error(msg.format(operation_name, self)) self.operations[key] = operation class WsdlOperation(WsdlComponent): input = output = None soap_operation = None def __init__(self, elem, wsdl_document): super(WsdlOperation, self).__init__(elem, wsdl_document) self.faults = {} input_child = elem.find(WSDL_INPUT) if input_child is not None: self.input = WsdlInput(input_child, wsdl_document) output_child = elem.find(WSDL_OUTPUT) if output_child is not None: self.output = WsdlOutput(output_child, wsdl_document) for fault_child in elem.iterfind(WSDL_FAULT): fault = WsdlFault(fault_child, wsdl_document) if fault.name is None: continue elif fault.local_name in self.faults: msg = "duplicated fault {!r} for {!r}" wsdl_document.parse_error(msg.format(fault.local_name, self)) self.faults[fault.local_name] = fault if input_child is not None and output_child is not None: children = self.elem[:] input_pos = children.index(input_child) output_pos = children.index(output_child) if input_pos < output_pos: self.transmission = 'request-response' else: self.transmission = 'solicit-response' elif input_child is not None: self.transmission = 'one-way' elif output_child is not None: self.transmission = 'notification' else: self.transmission = None @property def key(self): return self.local_name, \ getattr(self.input, 'local_name', None), \ getattr(self.output, 'local_name', None) @property def soap_action(self): """The SOAP operation's action URI if any, `None` otherwise.""" if self.soap_operation is not None: return self.soap_operation.get('soapAction') @property def soap_style(self): """The SOAP operation's style if any, `None` otherwise.""" if self.soap_operation is not None: style = self.soap_operation.get('style') return style if style in ('rpc', 'document') else 'document' class WsdlMessageReference(WsdlComponent): message = None def __init__(self, elem, wsdl_document): super(WsdlMessageReference, self).__init__(elem, wsdl_document) message_name = self._parse_reference(elem, 'message') try: self.message = wsdl_document.maps.messages[message_name] except KeyError: if message_name: msg = "unknown message {!r} for {!r}" wsdl_document.parse_error(msg.format(message_name, self)) class WsdlInput(WsdlMessageReference): soap_headers = () soap_body = None class WsdlOutput(WsdlMessageReference): soap_headers = () soap_body = None class WsdlFault(WsdlMessageReference): soap_fault = None class SoapParameter(WsdlComponent): @property def use(self): use = self.elem.get('use') return use if use in ('literal', 'encoded') else None @property def encoding_style(self): return self.elem.get('encodingStyle') @property def namespace(self): return self.elem.get('namespace', '') class SoapBody(SoapParameter): """Class for soap:body bindings.""" def __init__(self, elem, wsdl_document): super(SoapBody, self).__init__(elem, wsdl_document) self.parts = elem.get('parts', '').split() class SoapFault(SoapParameter): """Class for soap:fault bindings.""" class SoapHeader(WsdlMessageReference, SoapParameter): """Class for soap:header bindings.""" part = None def __init__(self, elem, wsdl_document): super(SoapHeader, self).__init__(elem, wsdl_document) if self.message is not None and 'part' in elem.attrib: try: self.part = self.message.parts[elem.attrib['part']] except KeyError: msg = "missing message part {!r}" wsdl_document.parse_error(msg.format(elem.attrib['part'])) if elem.tag == SOAP_HEADER: self.faults = [SoapHeaderFault(e, wsdl_document) for e in elem.iterfind(SOAP_HEADERFAULT)] class SoapHeaderFault(SoapHeader): """Class for soap:headerfault bindings.""" class WsdlBinding(WsdlComponent): port_type = None """The wsdl:portType definition related to the binding instance.""" soap_binding = None """The SOAP binding element if any, `None` otherwise.""" def __init__(self, elem, wsdl_document): super(WsdlBinding, self).__init__(elem, wsdl_document) self.operations = {} if wsdl_document.soap_binding: self.soap_binding = elem.find(SOAP_BINDING) if self.soap_binding is None: msg = "missing soap:binding element for {!r}" wsdl_document.parse_error(msg.format(self)) port_type_name = self._parse_reference(elem, 'type') try: self.port_type = wsdl_document.maps.port_types[port_type_name] except KeyError: msg = "missing port type {!r} for {!r}" wsdl_document.parse_error(msg.format(port_type_name, self)) return # pragma: no cover for op_child in elem.iterfind(WSDL_OPERATION): op_name = op_child.get('name') if op_name is None: continue # Ignore, missing name is already caught by XSD validator input_child = op_child.find(WSDL_INPUT) input_name = None if input_child is None else input_child.get('name') output_child = op_child.find(WSDL_OUTPUT) output_name = None if output_child is None else output_child.get('name') key = op_name, input_name, output_name if key in self.operations: msg = "duplicated operation {!r} for {!r}" wsdl_document.parse_error(msg.format(op_name, self)) try: operation = self.port_type.operations[key] except KeyError: msg = "operation {!r} not found for {!r}" wsdl_document.parse_error(msg.format(op_name, self)) continue # pragma: no cover else: self.operations[key] = operation if wsdl_document.soap_binding: operation.soap_operation = op_child.find(SOAP_OPERATION) if input_child is not None: for body_child in input_child.iterfind(SOAP_BODY): operation.input.soap_body = SoapBody(body_child, wsdl_document) break operation.input.soap_headers = [ SoapHeader(e, wsdl_document) for e in input_child.iterfind(SOAP_HEADER) ] if output_child is not None: for body_child in output_child.iterfind(SOAP_BODY): operation.output.soap_body = SoapBody(body_child, wsdl_document) break operation.output.soap_headers = [ SoapHeader(e, wsdl_document) for e in output_child.iterfind(SOAP_HEADER) ] for fault_child in op_child.iterfind(WSDL_FAULT): fault = WsdlFault(fault_child, wsdl_document) if fault.name and fault.local_name not in operation.faults: msg = "missing fault {!r} in {!r}" wsdl_document.parse_error(msg.format(fault.local_name, operation)) for soap_fault_child in fault_child.iterfind(SOAP_FAULT): fault = SoapFault(soap_fault_child, wsdl_document) if fault.name: try: operation.faults[fault.local_name].soap_fault = fault except KeyError: msg = "missing fault {!r} in {!r}" wsdl_document.parse_error(msg.format(fault.local_name, operation)) @property def soap_transport(self): """The SOAP binding's transport URI if any, `None` otherwise.""" if self.soap_binding is not None: return self.soap_binding.get('transport') @property def soap_style(self): """The SOAP binding's style if any, `None` otherwise.""" if self.soap_binding is not None: style = self.soap_binding.get('style') return style if style in ('rpc', 'document') else 'document' class WsdlPort(WsdlComponent): binding = None soap_location = None def __init__(self, elem, wsdl_document): super(WsdlPort, self).__init__(elem, wsdl_document) binding_name = self._parse_reference(elem, 'binding') try: self.binding = wsdl_document.maps.bindings[binding_name] except KeyError: if binding_name: msg = "unknown binding {!r} for {!r} output" wsdl_document.parse_error(msg.format(binding_name, self)) if wsdl_document.soap_binding: for child in elem.iterfind(SOAP_ADDRESS): self.soap_location = child.get('location') break class WsdlService(WsdlComponent): def __init__(self, elem, wsdl_document): super(WsdlService, self).__init__(elem, wsdl_document) self.ports = {} for port_child in elem.iterfind(WSDL_PORT): port = WsdlPort(port_child, wsdl_document) port_name = port.local_name if port_name is None: continue # Ignore, missing name is already caught by XSD validator elif port_name in self.ports: msg = "duplicated port {!r} for {!r}" wsdl_document.parse_error(msg.format(port.prefixed_name, self)) else: self.ports[port_name] = port class Wsdl11Document(XmlDocument): """ Class for WSDL 1.1 documents. :param source: a string containing XML data or a file path or an URL or a \ file like object or an ElementTree or an Element. :param cls: class to use for building the schema instance (for default \ :class:`XMLSchema10` is used). :param validation: the XSD validation mode to use for validating the XML document, \ that can be 'strict' (default), 'lax' or 'skip'. :param maps: WSDL definitions shared maps. :param namespaces: is an optional mapping from namespace prefix to URI. :param locations: resource location hints, that can be a dictionary or a \ sequence of couples (namespace URI, resource URL). :param base_url: the base URL for base :class:`xmlschema.XMLResource` initialization. :param allow: the security mode for base :class:`xmlschema.XMLResource` initialization. :param defuse: the defuse mode for base :class:`xmlschema.XMLResource` initialization. :param timeout: the timeout for base :class:`xmlschema.XMLResource` initialization. """ target_namespace = '' soap_binding = False def __init__(self, source, cls=None, validation='strict', namespaces=None, maps=None, locations=None, base_url=None, allow='all', defuse='remote', timeout=300): if maps is None: if cls is None: cls = XMLSchema10 self.schema = cls(source=os.path.join(SCHEMAS_DIR, 'WSDL/wsdl.xsd')) self.maps = Wsdl11Maps(self) else: self.schema = maps.wsdl_document.schema self.maps = maps if locations: self.locations = NamespaceResourcesMap(locations) else: self.locations = NamespaceResourcesMap() super(Wsdl11Document, self).__init__( source=source, schema=self.schema, validation=validation, namespaces=namespaces, locations=locations, base_url=base_url, allow=allow, defuse=defuse, timeout=timeout, ) @property def imports(self): """WSDL 1.1 imports of XSD or WSDL additional resources.""" return self.maps.imports @property def messages(self): """WSDL 1.1 messages.""" return self.maps.messages @property def port_types(self): """WSDL 1.1 port types.""" return self.maps.port_types @property def bindings(self): """WSDL 1.1 bindings.""" return self.maps.bindings @property def services(self): """WSDL 1.1 services.""" return self.maps.services def parse(self, source, lazy=False): if lazy: raise WsdlParseError("{!r} instance cannot be lazy".format(self.__class__)) super(Wsdl11Document, self).parse(source, lazy) self.target_namespace = self._root.get('targetNamespace', '') self.soap_binding = SOAP_NAMESPACE in self.namespaces.values() if self.namespace == XSD_NAMESPACE: self.schema.__class__(self, global_maps=self.schema.maps, locations=self.locations) return if self is self.maps.wsdl_document: self.maps.clear() self._parse_imports() self._parse_types() self._parse_messages() self._parse_port_types() self._parse_bindings() self._parse_services() def parse_error(self, message): if self.validation == 'strict': raise WsdlParseError(message) elif self.validation == 'lax': self.errors.append(WsdlParseError(message)) def _parse_types(self): path = '{}/{}'.format(WSDL_TYPES, XSD_SCHEMA) for child in self._root.iterfind(path): source = self.subresource(child) self.schema.__class__(source, global_maps=self.schema.maps) def _parse_messages(self): for child in self.iterfind(WSDL_MESSAGE): message = WsdlMessage(child, self) if message.name in self.maps.messages: self.parse_error("duplicated message {!r}".format(message.prefixed_name)) else: self.maps.messages[message.name] = message def _parse_port_types(self): for child in self.iterfind(WSDL_PORT_TYPE): port_type = WsdlPortType(child, self) if port_type.name in self.maps.port_types: self.parse_error("duplicated port type {!r}".format(port_type.prefixed_name)) else: self.maps.port_types[port_type.name] = port_type def _parse_bindings(self): for child in self.iterfind(WSDL_BINDING): binding = WsdlBinding(child, self) if binding.name in self.maps.bindings: self.parse_error("duplicated binding {!r}".format(binding.prefixed_name)) else: self.maps.bindings[binding.name] = binding def _parse_services(self): for child in self.iterfind(WSDL_SERVICE): service = WsdlService(child, self) if service.name in self.maps.services: self.parse_error("duplicated service {!r}".format(service.prefixed_name)) else: self.maps.services[service.name] = service def _parse_imports(self): namespace_imports = NamespaceResourcesMap(map( lambda x: (x.get('namespace', ''), x.get('location', '')), filter(lambda x: x.tag == WSDL_IMPORT, self.root) )) for namespace, locations in namespace_imports.items(): locations = [url for url in locations if url] try: locations.extend(self.locations[namespace]) except KeyError: pass import_error = None for url in locations: try: self.import_namespace(namespace, url, self.base_url) except (OSError, IOError) as err: if import_error is None: import_error = err except SyntaxError as err: msg = "cannot import namespace %r: %s." % (namespace, err) self.parse_error(msg) except XMLSchemaValueError as err: self.parse_error(err) else: break else: if import_error is not None: msg = "import of namespace {!r} from {!r} failed: {}." self.parse_error(msg.format(namespace, locations, str(import_error))) self.maps.imports[namespace] = None def import_namespace(self, namespace, location, base_url=None): if namespace == self.target_namespace: msg = "namespace to import must be different from the " \ "'targetNamespace' of the WSDL document" raise XMLSchemaValueError(msg) elif namespace in self.maps.imports: return self.maps.imports[namespace] url = fetch_resource(location, base_url or self.base_url) wsdl_document = self.__class__( source=url, maps=self.maps, namespaces=self._namespaces, validation=self.validation, base_url=self.base_url, allow=self.allow, defuse=self.defuse, timeout=self.timeout, ) if wsdl_document.target_namespace != namespace: msg = 'imported {!r} has an unmatched namespace {!r}' self.parse_error(msg.format(wsdl_document, namespace)) self.maps.imports[namespace] = wsdl_document return wsdl_document ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/helpers.py���������������������������������������������������������������0000664�0000000�0000000�00000025547�14211403446�0017563�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import re from collections import Counter from decimal import Decimal from typing import Any, Callable, Iterator, List, MutableMapping, \ Optional, Tuple, Union from .exceptions import XMLSchemaValueError, XMLSchemaTypeError from .names import XSI_SCHEMA_LOCATION, XSI_NONS_SCHEMA_LOCATION from .aliases import ElementType, NamespacesType, AtomicValueType, NumericValueType ### # Helper functions for QNames NAMESPACE_PATTERN = re.compile(r'{([^}]*)}') def get_namespace(qname: str, namespaces: Optional[NamespacesType] = None) -> str: """ Returns the namespace URI associated with a QName. If a namespace map is provided tries to resolve a prefixed QName and then to extract the namespace. :param qname: an extended QName or a local name or a prefixed QName. :param namespaces: optional mapping from prefixes to namespace URIs. """ if not qname: return '' elif qname[0] != '{': if namespaces is None: return '' qname = get_extended_qname(qname, namespaces) try: return NAMESPACE_PATTERN.match(qname).group(1) # type: ignore[union-attr] except (AttributeError, TypeError): return '' def get_qname(uri: Optional[str], name: str) -> str: """ Returns an expanded QName from URI and local part. If any argument has boolean value `False` or if the name is already an expanded QName, returns the *name* argument. :param uri: namespace URI :param name: local or qualified name :return: string or the name argument """ if not uri or not name or name[0] in ('{', '.', '/', '['): return name else: return '{%s}%s' % (uri, name) def local_name(qname: str) -> str: """ Return the local part of an expanded QName or a prefixed name. If the name is `None` or empty returns the *name* argument. :param qname: an expanded QName or a prefixed name or a local name. """ try: if qname[0] == '{': _, qname = qname.split('}') elif ':' in qname: _, qname = qname.split(':') except IndexError: return '' except ValueError: raise XMLSchemaValueError("the argument 'qname' has a wrong format: %r" % qname) except TypeError: raise XMLSchemaTypeError("the argument 'qname' must be a string") else: return qname def get_prefixed_qname(qname: str, namespaces: Optional[MutableMapping[str, str]], use_empty: bool = True) -> str: """ Get the prefixed form of a QName, using a namespace map. :param qname: an extended QName or a local name or a prefixed QName. :param namespaces: an optional mapping from prefixes to namespace URIs. :param use_empty: if `True` use the empty prefix for mapping. """ if not namespaces or not qname or qname[0] != '{': return qname namespace = get_namespace(qname) prefixes = [x for x in namespaces if namespaces[x] == namespace] if not prefixes: return qname elif prefixes[0]: return '%s:%s' % (prefixes[0], qname.split('}', 1)[1]) elif len(prefixes) > 1: return '%s:%s' % (prefixes[1], qname.split('}', 1)[1]) elif use_empty: return qname.split('}', 1)[1] else: return qname def get_extended_qname(qname: str, namespaces: Optional[MutableMapping[str, str]]) -> str: """ Get the extended form of a QName, using a namespace map. Local names are mapped to the default namespace. :param qname: a prefixed QName or a local name or an extended QName. :param namespaces: an optional mapping from prefixes to namespace URIs. """ if not namespaces: return qname try: if qname[0] == '{': return qname except IndexError: return qname try: prefix, name = qname.split(':', 1) except ValueError: if not namespaces.get(''): return qname else: return '{%s}%s' % (namespaces[''], qname) else: try: uri = namespaces[prefix] except KeyError: return qname else: return '{%s}%s' % (uri, name) if uri else name ### # Helper functions for ElementTree structures def is_etree_element(obj: object) -> bool: """A checker for valid ElementTree elements that excludes XsdElement objects.""" return hasattr(obj, 'append') and hasattr(obj, 'tag') and hasattr(obj, 'attrib') def is_etree_document(obj: object) -> bool: """A checker for valid ElementTree objects.""" return hasattr(obj, 'getroot') and hasattr(obj, 'parse') and hasattr(obj, 'iter') def etree_iterpath(elem: ElementType, tag: Optional[str] = None, path: str = '.', namespaces: Optional[NamespacesType] = None, add_position: bool = False) -> Iterator[Tuple[ElementType, str]]: """ Creates an iterator for the element and its subelements that yield elements and paths. If tag is not `None` or '*', only elements whose matches tag are returned from the iterator. :param elem: the element to iterate. :param tag: tag filtering. :param path: the current path, '.' for default. :param namespaces: is an optional mapping from namespace prefix to URI. :param add_position: add context position to child elements that appear multiple times. """ if tag == "*": tag = None if not path: path = '.' if tag is None or elem.tag == tag: yield elem, path if add_position: children_tags = Counter(e.tag for e in elem) positions = Counter(t for t in children_tags if children_tags[t] > 1) else: positions = Counter() for child in elem: if callable(child.tag): continue # Skip lxml comments child_name = child.tag if namespaces is None else get_prefixed_qname(child.tag, namespaces) if path == '/': child_path = '/%s' % child_name else: child_path = '/'.join((path, child_name)) if child.tag in positions: child_path += '[%d]' % positions[child.tag] positions[child.tag] += 1 yield from etree_iterpath(child, tag, child_path, namespaces, add_position) def etree_getpath(elem: ElementType, root: ElementType, namespaces: Optional[NamespacesType] = None, relative: bool = True, add_position: bool = False, parent_path: bool = False) -> Optional[str]: """ Returns the XPath path from *root* to descendant *elem* element. :param elem: the descendant element. :param root: the root element. :param namespaces: an optional mapping from namespace prefix to URI. :param relative: returns a relative path. :param add_position: add context position to child elements that appear multiple times. :param parent_path: if set to `True` returns the parent path. Default is `False`. :return: An XPath expression or `None` if *elem* is not a descendant of *root*. """ if relative: path = '.' elif namespaces: path = '/%s' % get_prefixed_qname(root.tag, namespaces) else: path = '/%s' % root.tag if not parent_path: for e, path in etree_iterpath(root, elem.tag, path, namespaces, add_position): if e is elem: return path else: for e, path in etree_iterpath(root, None, path, namespaces, add_position): if elem in e: return path return None def etree_iter_location_hints(elem: ElementType) -> Iterator[Tuple[Any, Any]]: """Yields schema location hints contained in the attributes of an element.""" if XSI_SCHEMA_LOCATION in elem.attrib: locations = elem.attrib[XSI_SCHEMA_LOCATION].split() for ns, url in zip(locations[0::2], locations[1::2]): yield ns, url if XSI_NONS_SCHEMA_LOCATION in elem.attrib: for url in elem.attrib[XSI_NONS_SCHEMA_LOCATION].split(): yield '', url def prune_etree(root: ElementType, selector: Callable[[ElementType], bool]) \ -> Optional[bool]: """ Removes from an tree structure the elements that verify the selector function. The checking and eventual removals are performed using a breadth-first visit method. :param root: the root element of the tree. :param selector: the single argument function to apply on each visited node. :return: `True` if the root node verify the selector function, `None` otherwise. """ def _prune_subtree(elem: ElementType) -> None: for child in elem[:]: if selector(child): elem.remove(child) for child in elem: _prune_subtree(child) if selector(root): del root[:] return True _prune_subtree(root) return None def count_digits(number: NumericValueType) -> Tuple[int, int]: """ Counts the digits of a number. :param number: an int or a float or a Decimal or a string representing a number. :return: a couple with the number of digits of the integer part and \ the number of digits of the decimal part. """ if isinstance(number, str): number = str(Decimal(number)).lstrip('-+') elif isinstance(number, bytes): number = str(Decimal(number.decode())).lstrip('-+') else: number = str(number).lstrip('-+') if 'E' in number: significand, _, _exponent = number.partition('E') elif 'e' in number: significand, _, _exponent = number.partition('e') elif '.' not in number: return len(number.lstrip('0')), 0 else: integer_part, _, decimal_part = number.partition('.') return len(integer_part.lstrip('0')), len(decimal_part.rstrip('0')) significand = significand.strip('0') exponent = int(_exponent) num_digits = len(significand) - 1 if '.' in significand else len(significand) if exponent > 0: return num_digits + exponent, 0 else: return 0, num_digits - exponent - 1 def strictly_equal(obj1: object, obj2: object) -> bool: """Checks if the objects are equal and are of the same type.""" return obj1 == obj2 and type(obj1) is type(obj2) def raw_xml_encode(value: Union[None, AtomicValueType, List[AtomicValueType], Tuple[AtomicValueType, ...]]) -> Optional[str]: """Encodes a simple value to XML.""" if isinstance(value, bool): return 'true' if value else 'false' elif isinstance(value, (list, tuple)): return ' '.join(str(e) for e in value) else: return str(value) if value is not None else None ���������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/limits.py����������������������������������������������������������������0000664�0000000�0000000�00000001245�14211403446�0017407�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """Package protection limits. Values can be changed after import to set different limits.""" MAX_XML_DEPTH = 9999 """ Maximum depth of XML data. An `XMLSchemaValidationError` is raised if this limit is exceeded. """ MAX_MODEL_DEPTH = 15 """ Maximum XSD model group depth. An `XMLSchemaModelDepthError` is raised if this limit is exceeded. """ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/names.py�����������������������������������������������������������������0000664�0000000�0000000�00000021173�14211403446�0017213�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains namespace definitions for W3C core standards. """ import os ### # Namespace URIs for schemas XSD_NAMESPACE = 'http://www.w3.org/2001/XMLSchema' "URI of the XML Schema Definition namespace (xs|xsd)" XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' "URI of the XML Schema Instance namespace (xsi)" XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace' "URI of the XML namespace (xml)" XHTML_NAMESPACE = 'http://www.w3.org/1999/xhtml' XHTML_DATATYPES_NAMESPACE = 'http://www.w3.org/1999/xhtml/datatypes/' "URIs of the Extensible Hypertext Markup Language namespace (html)" XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink' "URI of the XML Linking Language (XLink)" XSLT_NAMESPACE = "http://www.w3.org/1999/XSL/Transform" "URI of the XSL Transformations namespace (xslt)" HFP_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-hasFacetAndProperty' "URI of the XML Schema has Facet and Property namespace (hfp)" VC_NAMESPACE = 'http://www.w3.org/2007/XMLSchema-versioning' "URI of the XML Schema Versioning namespace (vc)" ### # Namespace URIs for XML documents WSDL_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/' SOAP_NAMESPACE = 'http://schemas.xmlsoap.org/wsdl/soap/' SOAP_ENVELOPE_NAMESPACE = 'http://schemas.xmlsoap.org/soap/envelope/' SOAP_ENCODING_NAMESPACE = 'http://schemas.xmlsoap.org/soap/encoding/' ### # Schema location hints SCHEMAS_DIR = os.path.join(os.path.dirname(__file__), 'schemas/') LOCATION_HINTS = { # Locally saved schemas # HFP_NAMESPACE: os.path.join(SCHEMAS_DIR, 'HFP/XMLSchema-hasFacetAndProperty_minimal.xsd'), VC_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSI/XMLSchema-versioning.xsd'), XLINK_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XLINK/xlink.xsd'), XHTML_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XHTML/xhtml1-strict.xsd'), WSDL_NAMESPACE: os.path.join(SCHEMAS_DIR, 'WSDL/wsdl.xsd'), SOAP_NAMESPACE: os.path.join(SCHEMAS_DIR, 'WSDL/wsdl-soap.xsd'), SOAP_ENVELOPE_NAMESPACE: os.path.join(SCHEMAS_DIR, 'WSDL/soap-envelope.xsd'), SOAP_ENCODING_NAMESPACE: os.path.join(SCHEMAS_DIR, 'WSDL/soap-encoding.xsd'), # Remote locations: contributors can propose additional official locations # for other namespaces for extending this list. XSLT_NAMESPACE: os.path.join(SCHEMAS_DIR, 'http://www.w3.org/2007/schema-for-xslt20.xsd'), } ### # Elements and attributes names _VC_TEMPLATE = '{http://www.w3.org/2007/XMLSchema-versioning}%s' _XML_TEMPLATE = '{http://www.w3.org/XML/1998/namespace}%s' _XSD_TEMPLATE = '{http://www.w3.org/2001/XMLSchema}%s' _XSI_TEMPLATE = '{http://www.w3.org/2001/XMLSchema-instance}%s' # # Version Control attributes (XSD 1.1) VC_MIN_VERSION = _VC_TEMPLATE % 'minVersion' VC_MAX_VERSION = _VC_TEMPLATE % 'maxVersion' VC_TYPE_AVAILABLE = _VC_TEMPLATE % 'typeAvailable' VC_TYPE_UNAVAILABLE = _VC_TEMPLATE % 'typeUnavailable' VC_FACET_AVAILABLE = _VC_TEMPLATE % 'facetAvailable' VC_FACET_UNAVAILABLE = _VC_TEMPLATE % 'facetUnavailable' # # XML attributes XML_LANG = _XML_TEMPLATE % 'lang' XML_SPACE = _XML_TEMPLATE % 'space' XML_BASE = _XML_TEMPLATE % 'base' XML_ID = _XML_TEMPLATE % 'id' XML_SPECIAL_ATTRS = _XML_TEMPLATE % 'specialAttrs' # # XML Schema Instance attributes XSI_NIL = _XSI_TEMPLATE % 'nil' XSI_TYPE = _XSI_TEMPLATE % 'type' XSI_SCHEMA_LOCATION = _XSI_TEMPLATE % 'schemaLocation' XSI_NONS_SCHEMA_LOCATION = _XSI_TEMPLATE % 'noNamespaceSchemaLocation' # # XML Schema fully qualified names XSD_SCHEMA = _XSD_TEMPLATE % 'schema' # Annotations XSD_ANNOTATION = _XSD_TEMPLATE % 'annotation' XSD_APPINFO = _XSD_TEMPLATE % 'appinfo' XSD_DOCUMENTATION = _XSD_TEMPLATE % 'documentation' # Composing schemas XSD_INCLUDE = _XSD_TEMPLATE % 'include' XSD_IMPORT = _XSD_TEMPLATE % 'import' XSD_REDEFINE = _XSD_TEMPLATE % 'redefine' XSD_OVERRIDE = _XSD_TEMPLATE % 'override' # Structures XSD_SIMPLE_TYPE = _XSD_TEMPLATE % 'simpleType' XSD_COMPLEX_TYPE = _XSD_TEMPLATE % 'complexType' XSD_ATTRIBUTE = _XSD_TEMPLATE % 'attribute' XSD_ELEMENT = _XSD_TEMPLATE % 'element' XSD_NOTATION = _XSD_TEMPLATE % 'notation' # Grouping XSD_GROUP = _XSD_TEMPLATE % 'group' XSD_ATTRIBUTE_GROUP = _XSD_TEMPLATE % 'attributeGroup' # simpleType declaration elements XSD_RESTRICTION = _XSD_TEMPLATE % 'restriction' XSD_LIST = _XSD_TEMPLATE % 'list' XSD_UNION = _XSD_TEMPLATE % 'union' # complexType content XSD_EXTENSION = _XSD_TEMPLATE % 'extension' XSD_SEQUENCE = _XSD_TEMPLATE % 'sequence' XSD_CHOICE = _XSD_TEMPLATE % 'choice' XSD_ALL = _XSD_TEMPLATE % 'all' XSD_ANY = _XSD_TEMPLATE % 'any' XSD_SIMPLE_CONTENT = _XSD_TEMPLATE % 'simpleContent' XSD_COMPLEX_CONTENT = _XSD_TEMPLATE % 'complexContent' XSD_ANY_ATTRIBUTE = _XSD_TEMPLATE % 'anyAttribute' # # Facets (lexical, pre-lexical and value-based facets) XSD_ENUMERATION = _XSD_TEMPLATE % 'enumeration' XSD_LENGTH = _XSD_TEMPLATE % 'length' XSD_MIN_LENGTH = _XSD_TEMPLATE % 'minLength' XSD_MAX_LENGTH = _XSD_TEMPLATE % 'maxLength' XSD_PATTERN = _XSD_TEMPLATE % 'pattern' # lexical facet XSD_WHITE_SPACE = _XSD_TEMPLATE % 'whiteSpace' # pre-lexical facet XSD_MAX_INCLUSIVE = _XSD_TEMPLATE % 'maxInclusive' XSD_MAX_EXCLUSIVE = _XSD_TEMPLATE % 'maxExclusive' XSD_MIN_INCLUSIVE = _XSD_TEMPLATE % 'minInclusive' XSD_MIN_EXCLUSIVE = _XSD_TEMPLATE % 'minExclusive' XSD_TOTAL_DIGITS = _XSD_TEMPLATE % 'totalDigits' XSD_FRACTION_DIGITS = _XSD_TEMPLATE % 'fractionDigits' # XSD 1.1 elements XSD_OPEN_CONTENT = _XSD_TEMPLATE % 'openContent' # open content model XSD_DEFAULT_OPEN_CONTENT = _XSD_TEMPLATE % 'defaultOpenContent' # default open content model XSD_ALTERNATIVE = _XSD_TEMPLATE % 'alternative' # conditional type assignment XSD_ASSERT = _XSD_TEMPLATE % 'assert' # complex type assertions XSD_ASSERTION = _XSD_TEMPLATE % 'assertion' # facets XSD_EXPLICIT_TIMEZONE = _XSD_TEMPLATE % 'explicitTimezone' # Identity constraints XSD_UNIQUE = _XSD_TEMPLATE % 'unique' XSD_KEY = _XSD_TEMPLATE % 'key' XSD_KEYREF = _XSD_TEMPLATE % 'keyref' XSD_SELECTOR = _XSD_TEMPLATE % 'selector' XSD_FIELD = _XSD_TEMPLATE % 'field' # # XSD Builtin Types # Special XSD built-in types. XSD_ANY_TYPE = _XSD_TEMPLATE % 'anyType' XSD_ANY_SIMPLE_TYPE = _XSD_TEMPLATE % 'anySimpleType' XSD_ANY_ATOMIC_TYPE = _XSD_TEMPLATE % 'anyAtomicType' # Other XSD built-in types. XSD_DECIMAL = _XSD_TEMPLATE % 'decimal' XSD_STRING = _XSD_TEMPLATE % 'string' XSD_DOUBLE = _XSD_TEMPLATE % 'double' XSD_FLOAT = _XSD_TEMPLATE % 'float' XSD_DATE = _XSD_TEMPLATE % 'date' XSD_DATETIME = _XSD_TEMPLATE % 'dateTime' XSD_GDAY = _XSD_TEMPLATE % 'gDay' XSD_GMONTH = _XSD_TEMPLATE % 'gMonth' XSD_GMONTH_DAY = _XSD_TEMPLATE % 'gMonthDay' XSD_GYEAR = _XSD_TEMPLATE % 'gYear' XSD_GYEAR_MONTH = _XSD_TEMPLATE % 'gYearMonth' XSD_TIME = _XSD_TEMPLATE % 'time' XSD_DURATION = _XSD_TEMPLATE % 'duration' XSD_QNAME = _XSD_TEMPLATE % 'QName' XSD_NOTATION_TYPE = _XSD_TEMPLATE % 'NOTATION' XSD_ANY_URI = _XSD_TEMPLATE % 'anyURI' XSD_BOOLEAN = _XSD_TEMPLATE % 'boolean' XSD_BASE64_BINARY = _XSD_TEMPLATE % 'base64Binary' XSD_HEX_BINARY = _XSD_TEMPLATE % 'hexBinary' XSD_NORMALIZED_STRING = _XSD_TEMPLATE % 'normalizedString' XSD_TOKEN = _XSD_TEMPLATE % 'token' XSD_LANGUAGE = _XSD_TEMPLATE % 'language' XSD_NAME = _XSD_TEMPLATE % 'Name' XSD_NCNAME = _XSD_TEMPLATE % 'NCName' XSD_ID = _XSD_TEMPLATE % 'ID' XSD_IDREF = _XSD_TEMPLATE % 'IDREF' XSD_ENTITY = _XSD_TEMPLATE % 'ENTITY' XSD_NMTOKEN = _XSD_TEMPLATE % 'NMTOKEN' XSD_INTEGER = _XSD_TEMPLATE % 'integer' XSD_LONG = _XSD_TEMPLATE % 'long' XSD_INT = _XSD_TEMPLATE % 'int' XSD_SHORT = _XSD_TEMPLATE % 'short' XSD_BYTE = _XSD_TEMPLATE % 'byte' XSD_NON_NEGATIVE_INTEGER = _XSD_TEMPLATE % 'nonNegativeInteger' XSD_POSITIVE_INTEGER = _XSD_TEMPLATE % 'positiveInteger' XSD_UNSIGNED_LONG = _XSD_TEMPLATE % 'unsignedLong' XSD_UNSIGNED_INT = _XSD_TEMPLATE % 'unsignedInt' XSD_UNSIGNED_SHORT = _XSD_TEMPLATE % 'unsignedShort' XSD_UNSIGNED_BYTE = _XSD_TEMPLATE % 'unsignedByte' XSD_NON_POSITIVE_INTEGER = _XSD_TEMPLATE % 'nonPositiveInteger' XSD_NEGATIVE_INTEGER = _XSD_TEMPLATE % 'negativeInteger' # Built-in list types XSD_IDREFS = _XSD_TEMPLATE % 'IDREFS' XSD_ENTITIES = _XSD_TEMPLATE % 'ENTITIES' XSD_NMTOKENS = _XSD_TEMPLATE % 'NMTOKENS' # XSD 1.1 built-in types XSD_DATE_TIME_STAMP = _XSD_TEMPLATE % 'dateTimeStamp' XSD_DAY_TIME_DURATION = _XSD_TEMPLATE % 'dayTimeDuration' XSD_YEAR_MONTH_DURATION = _XSD_TEMPLATE % 'yearMonthDuration' XSD_ERROR = _XSD_TEMPLATE % 'error' XSD_UNTYPED_ATOMIC = _XSD_TEMPLATE % 'untypedAtomic' �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/namespaces.py������������������������������������������������������������0000664�0000000�0000000�00000024415�14211403446�0020231�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for managing maps related to namespaces. """ import re from typing import Any, Container, Dict, Iterator, List, Optional, MutableMapping, \ Mapping, TypeVar from .exceptions import XMLSchemaValueError, XMLSchemaTypeError from .helpers import local_name from .aliases import NamespacesType ### # Base classes for managing namespaces class NamespaceResourcesMap(MutableMapping[str, Any]): """ Dictionary for storing information about namespace resources. The values are lists of objects. Setting an existing value appends the object to the value. Setting a value with a list sets/replaces the value. """ __slots__ = ('_store',) def __init__(self, *args: Any, **kwargs: Any): self._store: Dict[str, List[Any]] = {} self.update(*args, **kwargs) def __getitem__(self, uri: str) -> Any: return self._store[uri] def __setitem__(self, uri: str, value: Any) -> None: if isinstance(value, list): self._store[uri] = value[:] else: try: self._store[uri].append(value) except KeyError: self._store[uri] = [value] def __delitem__(self, uri: str) -> None: del self._store[uri] def __iter__(self) -> Iterator[str]: return iter(self._store) def __len__(self) -> int: return len(self._store) def __repr__(self) -> str: return repr(self._store) def clear(self) -> None: self._store.clear() class NamespaceMapper(MutableMapping[str, str]): """ A class to map/unmap namespace prefixes to URIs. The mapped namespaces are automatically registered when set. Namespaces can be updated overwriting the existing registration or inserted using an alternative prefix. :param namespaces: initial data with namespace prefixes and URIs. \ The provided dictionary is bound with the instance, otherwise a new \ empty dictionary is used. :param strip_namespaces: if set to `True` uses name mapping methods that strip \ namespace information. """ __slots__ = '_namespaces', 'strip_namespaces', '__dict__' _namespaces: NamespacesType def __init__(self, namespaces: Optional[NamespacesType] = None, strip_namespaces: bool = False): if namespaces is None: self._namespaces = {} else: self._namespaces = namespaces self.strip_namespaces = strip_namespaces def __setattr__(self, name: str, value: str) -> None: if name == 'strip_namespaces': if value: self.map_qname = self.unmap_qname = self._local_name # type: ignore[assignment] elif getattr(self, 'strip_namespaces', False): self.map_qname = self._map_qname # type: ignore[assignment] self.unmap_qname = self._unmap_qname # type: ignore[assignment] super(NamespaceMapper, self).__setattr__(name, value) def __getitem__(self, prefix: str) -> str: return self._namespaces[prefix] def __setitem__(self, prefix: str, uri: str) -> None: self._namespaces[prefix] = uri def __delitem__(self, prefix: str) -> None: del self._namespaces[prefix] def __iter__(self) -> Iterator[str]: return iter(self._namespaces) def __len__(self) -> int: return len(self._namespaces) @property def namespaces(self) -> NamespacesType: return self._namespaces @property def default_namespace(self) -> Optional[str]: return self._namespaces.get('') def clear(self) -> None: self._namespaces.clear() def insert_item(self, prefix: str, uri: str) -> None: """ A method for setting an item that checks the prefix before inserting. In case of collision the prefix is changed adding a numerical suffix. """ if not prefix: if '' not in self._namespaces: self._namespaces[prefix] = uri return elif self._namespaces[''] == uri: return prefix = 'default' while prefix in self._namespaces: if self._namespaces[prefix] == uri: return match = re.search(r'(\d+)$', prefix) if match: index = int(match.group()) + 1 prefix = prefix[:match.span()[0]] + str(index) else: prefix += '0' self._namespaces[prefix] = uri def _map_qname(self, qname: str) -> str: """ Converts an extended QName to the prefixed format. Only registered namespaces are mapped. :param qname: a QName in extended format or a local name. :return: a QName in prefixed format or a local name. """ try: if qname[0] != '{' or not self._namespaces: return qname namespace, local_part = qname[1:].split('}') except IndexError: return qname except ValueError: raise XMLSchemaValueError("the argument 'qname' has a wrong format: %r" % qname) except TypeError: raise XMLSchemaTypeError("the argument 'qname' must be a string-like object") for prefix, uri in sorted(self._namespaces.items(), reverse=True): if uri == namespace: return '%s:%s' % (prefix, local_part) if prefix else local_part else: return qname map_qname = _map_qname def _unmap_qname(self, qname: str, name_table: Optional[Container[Optional[str]]] = None) -> str: """ Converts a QName in prefixed format or a local name to the extended QName format. Local names are converted only if a default namespace is included in the instance. If a *name_table* is provided a local name is mapped to the default namespace only if not found in the name table. :param qname: a QName in prefixed format or a local name :param name_table: an optional lookup table for checking local names. :return: a QName in extended format or a local name. """ try: if qname[0] == '{' or not self._namespaces: return qname prefix, name = qname.split(':') except IndexError: return qname except ValueError: if ':' in qname: raise XMLSchemaValueError("the argument 'qname' has a wrong format: %r" % qname) if not self._namespaces.get(''): return qname elif name_table is None or qname not in name_table: return '{%s}%s' % (self._namespaces.get(''), qname) else: return qname except (TypeError, AttributeError): raise XMLSchemaTypeError("the argument 'qname' must be a string-like object") else: try: uri = self._namespaces[prefix] except KeyError: return qname else: return '{%s}%s' % (uri, name) if uri else name unmap_qname = _unmap_qname @staticmethod def _local_name(qname: str, *_args: Any, **_kwargs: Any) -> str: return local_name(qname) def transfer(self, namespaces: NamespacesType) -> None: """ Transfers compatible prefix/namespace registrations from a dictionary. Registrations added to namespace mapper instance are deleted from argument. :param namespaces: a dictionary containing prefix/namespace registrations. """ transferred = [] for k, v in namespaces.items(): if k in self._namespaces: if v != self._namespaces[k]: continue else: self[k] = v transferred.append(k) for k in transferred: del namespaces[k] T = TypeVar('T') class NamespaceView(Mapping[str, T]): """ A read-only map for filtered access to a dictionary that stores objects mapped from QNames in extended format. """ __slots__ = 'target_dict', 'namespace', '_key_fmt' def __init__(self, qname_dict: Dict[str, T], namespace_uri: str): self.target_dict = qname_dict self.namespace = namespace_uri if namespace_uri: self._key_fmt = '{' + namespace_uri + '}%s' else: self._key_fmt = '%s' def __getitem__(self, key: str) -> T: return self.target_dict[self._key_fmt % key] def __len__(self) -> int: if not self.namespace: return len([k for k in self.target_dict if not k or k[0] != '{']) return len([k for k in self.target_dict if k and k[0] == '{' and self.namespace == k[1:k.rindex('}')]]) def __iter__(self) -> Iterator[str]: if not self.namespace: for k in self.target_dict: if not k or k[0] != '{': yield k else: for k in self.target_dict: if k and k[0] == '{' and self.namespace == k[1:k.rindex('}')]: yield k[k.rindex('}') + 1:] def __repr__(self) -> str: return '%s(%s)' % (self.__class__.__name__, str(self.as_dict())) def __contains__(self, key: object) -> bool: if isinstance(key, str): return self._key_fmt % key in self.target_dict return key in self.target_dict def __eq__(self, other: Any) -> Any: return self.as_dict() == other def as_dict(self, fqn_keys: bool = False) -> Dict[str, T]: if not self.namespace: return { k: v for k, v in self.target_dict.items() if not k or k[0] != '{' } elif fqn_keys: return { k: v for k, v in self.target_dict.items() if k and k[0] == '{' and self.namespace == k[1:k.rindex('}')] } else: return { k[k.rindex('}') + 1:]: v for k, v in self.target_dict.items() if k and k[0] == '{' and self.namespace == k[1:k.rindex('}')] } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/py.typed�����������������������������������������������������������������0000664�0000000�0000000�00000000000�14211403446�0017217�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/resources.py�������������������������������������������������������������0000664�0000000�0000000�00000147103�14211403446�0020124�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import copy import os.path import platform import re import string from io import StringIO, BytesIO from pathlib import Path, PurePath, PurePosixPath, PureWindowsPath from typing import cast, Any, AnyStr, Dict, Optional, IO, Iterator, List, \ MutableMapping, Union, Tuple from urllib.request import urlopen from urllib.parse import urlsplit, urlunsplit, unquote, quote_from_bytes from urllib.error import URLError from elementpath import iter_select, XPathContext, XPath2Parser from elementpath.protocols import ElementProtocol from .exceptions import XMLSchemaTypeError, XMLSchemaValueError, XMLResourceError from .names import XML_NAMESPACE from .etree import ElementTree, PyElementTree, SafeXMLParser, etree_tostring from .aliases import ElementType, ElementTreeType, NamespacesType, XMLSourceType, \ NormalizedLocationsType, LocationsType, NsmapType, ParentMapType from .helpers import get_namespace, is_etree_element, is_etree_document, \ etree_iter_location_hints DEFUSE_MODES = frozenset(('never', 'remote', 'nonlocal', 'always')) SECURITY_MODES = frozenset(('all', 'remote', 'local', 'sandbox', 'none')) ### # Restricted XPath parser for XML resources LAZY_XML_XPATH_SYMBOLS = frozenset(( 'position', 'last', 'not', 'and', 'or', '!=', '<=', '>=', '(', ')', 'text', '[', ']', '.', ',', '/', '|', '*', '=', '<', '>', ':', '@', '(end)', '(unknown)', '(invalid)', '(name)', '(string)', '(float)', '(decimal)', '(integer)' )) DRIVE_LETTERS = frozenset(string.ascii_letters) class LazyXPath2Parser(XPath2Parser): symbol_table = { k: v for k, v in XPath2Parser.symbol_table.items() # type: ignore[misc] if k in LAZY_XML_XPATH_SYMBOLS } SYMBOLS = LAZY_XML_XPATH_SYMBOLS class LazySelector: """A limited XPath selector class for lazy XML resources.""" def __init__(self, path: str, namespaces: Optional[NamespacesType] = None) -> None: self.parser = LazyXPath2Parser(namespaces, strict=False) self.path = path self.root_token = self.parser.parse(path) def __repr__(self) -> str: return '%s(path=%r)' % (self.__class__.__name__, self.path) def select(self, root: ElementProtocol, **kwargs: Any) -> List[ElementProtocol]: context = XPathContext(root, **kwargs) results = self.root_token.get_results(context) if not isinstance(results, list) or any(not is_etree_element(x) for x in results): msg = "XPath expressions on lazy resources can select only elements" raise XMLResourceError(msg) return results def iter_select(self, root: ElementProtocol, **kwargs: Any) -> Iterator[ElementProtocol]: context = XPathContext(root, **kwargs) for elem in self.root_token.select_results(context): if not is_etree_element(elem): msg = "XPath expressions on lazy resources can select only elements" raise XMLResourceError(msg) yield cast(ElementProtocol, elem) ### # URL normalization (that fixes many headaches :) class _PurePath(PurePath): """ A version of pathlib.PurePath adapted for managing the creation from URIs and the simple normalization of paths. """ _from_parts: Any _flavour: Any def __new__(cls, *args: str) -> '_PurePath': if cls is _PurePath: cls = _PureWindowsPath if os.name == 'nt' else _PurePosixPath return cast('_PurePath', cls._from_parts(args)) @classmethod def from_uri(cls, uri: str) -> '_PurePath': uri = uri.strip() if not uri: raise XMLSchemaValueError("Empty URI provided!") if uri.startswith(r'\\'): return _PureWindowsPath(uri) # UNC path elif uri.startswith('/'): return cls(uri) parts = urlsplit(uri) if not parts.scheme: return cls(uri) elif parts.scheme in DRIVE_LETTERS and len(parts.scheme) == 1: return _PureWindowsPath(uri) # Eg. k:/Python/lib/.... elif parts.scheme != 'file': return _PurePosixPath(unquote(parts.path)) # Get file URI path because urlsplit does not parse it well start = 7 if uri.startswith('file:///') else 5 if parts.query: path = uri[start:uri.index('?')] elif parts.fragment: path = uri[start:uri.index('#')] else: path = uri[start:] if ':' in path: # Windows path with a drive pos = path.index(':') if pos == 2 and path[0] == '/' and path[1] in DRIVE_LETTERS: return _PureWindowsPath(unquote(path[1:])) obj = _PureWindowsPath(unquote(path)) if len(obj.drive) != 2 or obj.drive[1] != ':': raise XMLSchemaValueError("Invalid URI {!r}".format(uri)) return obj if '\\' in path: return _PureWindowsPath(unquote(path)) return cls(unquote(path)) def as_uri(self) -> str: if not self.is_absolute(): uri: str = self._flavour.make_uri(self) while uri.startswith('file:/'): uri = uri.replace('file:/', 'file:', 1) return uri uri = cast(str, self._flavour.make_uri(self)) if isinstance(self, _PureWindowsPath) and str(self).startswith(r'\\'): # UNC format case: use the format where the host part is included # in the path part, to let urlopen() works. if not uri.startswith('file:////'): return uri.replace('file://', 'file:////') return uri def normalize(self) -> '_PurePath': normalized_path = self._flavour.pathmod.normpath(str(self)) return cast('_PurePath', self._from_parts((normalized_path,))) class _PurePosixPath(_PurePath, PurePosixPath): __slots__ = () class _PureWindowsPath(_PurePath, PureWindowsPath): __slots__ = () def normalize_url(url: str, base_url: Optional[str] = None, keep_relative: bool = False) -> str: """ Returns a normalized URL eventually joining it to a base URL if it's a relative path. Path names are converted to 'file' scheme URLs. :param url: a relative or absolute URL. :param base_url: a reference base URL. :param keep_relative: if set to `True` keeps relative file paths, which would \ not strictly conformant to specification (RFC 8089), because *urlopen()* doesn't \ accept a simple pathname. :return: a normalized URL string. """ url_parts = urlsplit(url) if not is_local_scheme(url_parts.scheme): return url_parts.geturl() path = _PurePath.from_uri(url) if path.is_absolute(): return path.normalize().as_uri() if base_url is not None: base_url_parts = urlsplit(base_url) base_path = _PurePath.from_uri(base_url) if is_local_scheme(base_url_parts.scheme): path = base_path.joinpath(path) elif not url_parts.scheme: path = base_path.joinpath(path).normalize() return urlunsplit(( base_url_parts.scheme, base_url_parts.netloc, quote_from_bytes(bytes(path)), url_parts.query, url_parts.fragment )) if path.is_absolute() or keep_relative: return path.normalize().as_uri() base_path = _PurePath(os.getcwd()) return base_path.joinpath(path).normalize().as_uri() ### # Internal helper functions def is_local_scheme(scheme: str) -> bool: return not scheme or scheme == 'file' or scheme in DRIVE_LETTERS def is_url(obj: object) -> bool: """Returns `True` if the provided object is an URL, `False` otherwise.""" if isinstance(obj, str): if '\n' in obj or obj.lstrip().startswith('<'): return False try: urlsplit(obj.strip()) except ValueError: return False elif isinstance(obj, bytes): if b'\n' in obj or obj.lstrip().startswith(b'<'): return False try: urlsplit(obj.strip()) except ValueError: return False else: return isinstance(obj, Path) return True def is_remote_url(obj: object) -> bool: if isinstance(obj, str): if '\n' in obj or obj.lstrip().startswith('<'): return False try: return not is_local_scheme(urlsplit(obj.strip()).scheme) except ValueError: return False elif isinstance(obj, bytes): if b'\n' in obj or obj.lstrip().startswith(b'<'): return False try: return not is_local_scheme(urlsplit(obj.strip().decode('utf-8')).scheme) except ValueError: return False else: return False def is_local_url(obj: object) -> bool: if isinstance(obj, str): if '\n' in obj or obj.lstrip().startswith('<'): return False try: return is_local_scheme(urlsplit(obj.strip()).scheme) except ValueError: return False elif isinstance(obj, bytes): if b'\n' in obj or obj.lstrip().startswith(b'<'): return False try: return is_local_scheme(urlsplit(obj.strip().decode('utf-8')).scheme) except ValueError: return False else: return isinstance(obj, Path) def url_path_is_file(url: str) -> bool: if not is_local_url(url): return False if os.path.isfile(url): return True path = unquote(urlsplit(normalize_url(url)).path) if path.startswith('/') and platform.system() == 'Windows': path = path[1:] return os.path.isfile(path) ### # API for XML resources def normalize_locations(locations: LocationsType, base_url: Optional[str] = None, keep_relative: bool = False) -> NormalizedLocationsType: """ Returns a list of normalized locations. The locations are normalized using the base URL of the instance. :param locations: a dictionary or a list of couples containing namespace location hints. :param base_url: the reference base URL for construct the normalized URL from the argument. :param keep_relative: if set to `True` keeps relative file paths, which would not strictly \ conformant to URL format specification. :return: a list of couples containing normalized namespace location hints. """ normalized_locations = [] if isinstance(locations, dict): for ns, value in locations.items(): if isinstance(value, list): normalized_locations.extend( [(ns, normalize_url(url, base_url, keep_relative)) for url in value] ) else: normalized_locations.append((ns, normalize_url(value, base_url, keep_relative))) else: normalized_locations.extend( [(ns, normalize_url(url, base_url, keep_relative)) for ns, url in locations] ) return normalized_locations def fetch_resource(location: str, base_url: Optional[str] = None, timeout: int = 30) -> str: """ Fetch a resource by trying to access it. If the resource is accessible returns its URL, otherwise raises an :class:`XMLResourceError`. :param location: an URL or a file path. :param base_url: reference base URL for normalizing local and relative URLs. :param timeout: the timeout in seconds for the connection attempt in case of remote data. :return: a normalized URL. """ if not location: raise XMLSchemaValueError("'location' argument must contain a not empty string") url = normalize_url(location, base_url) try: with urlopen(url, timeout=timeout): return url except URLError as err: # fallback joining the path without a base URL alt_url = normalize_url(location) if url == alt_url: raise XMLResourceError("cannot access to resource %r: %s" % (url, err.reason)) try: with urlopen(alt_url, timeout=timeout): return alt_url except URLError: raise XMLResourceError("cannot access to resource %r: %s" % (url, err.reason)) def fetch_schema_locations(source: Union['XMLResource', XMLSourceType], locations: Optional[LocationsType] = None, base_url: Optional[str] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 30) -> Tuple[str, NormalizedLocationsType]: """ Fetches schema location hints from an XML data source and a list of location hints. If an accessible schema location is not found raises a ValueError. :param source: can be an :class:`XMLResource` instance, a file-like object a path \ to a file or an URI of a resource or an Element instance or an ElementTree instance or \ a string containing the XML data. If the passed argument is not an :class:`XMLResource` \ instance a new one is built using this and *defuse*, *timeout* and *lazy* arguments. :param locations: a dictionary or dictionary items with additional schema location hints. :param base_url: the same argument of the :class:`XMLResource`. :param allow: the same argument of the :class:`XMLResource`. :param defuse: the same argument of the :class:`XMLResource`. :param timeout: the same argument of the :class:`XMLResource` but with a reduced default. :return: A 2-tuple with the URL referring to the first reachable schema resource \ and a list of dictionary items with normalized location hints. """ if not isinstance(source, XMLResource): resource = XMLResource(source, base_url, allow, defuse, timeout, lazy=True) else: resource = source base_url = resource.base_url namespace = resource.namespace locations = resource.get_locations(locations, root_only=False) if not locations: msg = "{!r} does not contain any schema location hint" raise XMLSchemaValueError(msg.format(source)) for ns, url in sorted(locations, key=lambda x: x[0] != namespace): try: return fetch_resource(url, base_url, timeout), locations except XMLResourceError: pass raise XMLSchemaValueError("not found a schema for XML data resource {!r}.".format(source)) def fetch_schema(source: Union['XMLResource', XMLSourceType], locations: Optional[LocationsType] = None, base_url: Optional[str] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 30) -> str: """ Like :meth:`fetch_schema_locations` but returns only a reachable location hint for a schema related to the source's namespace. """ return fetch_schema_locations(source, locations, base_url, allow, defuse, timeout)[0] def fetch_namespaces(source: XMLSourceType, base_url: Optional[str] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 30) -> NamespacesType: """ Fetches namespaces information from the XML data source. The argument *source* can be a string containing the XML document or file path or an url or a file-like object or an ElementTree instance or an Element instance. A dictionary with namespace mappings is returned. """ resource = XMLResource(source, base_url, allow, defuse, timeout, lazy=True) return resource.get_namespaces(root_only=False) class XMLResource: """ XML resource reader based on ElementTree and urllib. :param source: a string containing the XML document or file path or an URL or a \ file like object or an ElementTree or an Element. :param base_url: is an optional base URL, used for the normalization of relative paths \ when the URL of the resource can't be obtained from the source argument. For security \ access to a local file resource is always denied if the *base_url* is a remote URL. :param allow: defines the security mode for accessing resource locations. Can be \ 'all', 'remote', 'local', 'sandbox' or 'none'. Default is 'all' that means all types of \ URLs are allowed. With 'remote' only remote resource URLs are allowed. With 'local' \ only file paths and URLs are allowed. With 'sandbox' only file paths and URLs that \ are under the directory path identified by the *base_url* argument are allowed. \ If you provide 'none' no located resource is allowed. :param defuse: defines when to defuse XML data using a `SafeXMLParser`. Can be \ 'always', 'remote', 'nonlocal' or 'never'. For default defuses only remote XML data. \ With 'always' all the XML data that is not already parsed is defused. With 'nonlocal' \ it defuses unparsed data except local files. With 'never' no XML data source is defused. :param timeout: the timeout in seconds for the connection attempt in case of remote data. :param lazy: if a value `False` or 0 is provided the XML data is fully loaded into and \ processed from memory. For default only the root element of the source is loaded, \ except in case the *source* argument is an Element or an ElementTree instance. A \ positive integer also defines the depth at which the lazy resource can be better \ iterated (`True` means 1). """ # Protected attributes for data and resource location _source: XMLSourceType _root: ElementType _nsmap: Dict[ElementType, List[Tuple[str, str]]] _text: Optional[str] = None _url: Optional[str] = None _base_url: Optional[str] = None _parent_map: Optional[ParentMapType] = None _lazy: Union[bool, int] = False def __init__(self, source: XMLSourceType, base_url: Union[None, str, Path, bytes] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 300, lazy: Union[bool, int] = False) -> None: if isinstance(base_url, str): if not is_url(base_url): raise XMLSchemaValueError("'base_url' argument is not an URL") self._base_url = base_url elif isinstance(base_url, Path): self._base_url = str(base_url) elif isinstance(base_url, bytes): if not is_url(base_url): raise XMLSchemaValueError("'base_url' argument is not an URL") self._base_url = base_url.decode() elif base_url is not None: msg = "invalid type {!r} for argument 'base_url'" raise XMLSchemaTypeError(msg.format(type(base_url))) if not isinstance(allow, str): msg = "invalid type {!r} for argument 'allow'" raise XMLSchemaTypeError(msg.format(type(allow))) elif allow not in SECURITY_MODES: msg = "'allow' argument: {!r} is not a security mode" raise XMLSchemaValueError(msg.format(allow)) elif allow == 'sandbox' and self._base_url is None: msg = "block access to files out of sandbox requires 'base_url' to be set" raise XMLResourceError(msg) self._allow = allow if not isinstance(defuse, str): msg = "invalid type {!r} for argument 'defuse'" raise XMLSchemaTypeError(msg.format(type(defuse))) elif defuse not in DEFUSE_MODES: msg = "'defuse' argument: {!r} is not a defuse mode" raise XMLSchemaValueError(msg.format(defuse)) self._defuse = defuse if not isinstance(timeout, int): msg = "invalid type {!r} for argument 'timeout'" raise XMLSchemaTypeError(msg.format(type(timeout))) elif timeout <= 0: msg = "the argument 'timeout' must be a positive integer" raise XMLSchemaValueError(msg) self._timeout = timeout self.parse(source, lazy) def __repr__(self) -> str: return '%s(root=%r)' % (self.__class__.__name__, self._root) @property def source(self) -> XMLSourceType: """The XML data source.""" return self._source @property def root(self) -> ElementType: """The XML tree root Element.""" return self._root @property def text(self) -> Optional[str]: """The XML text source, `None` if it's not available.""" return self._text @property def name(self) -> Optional[str]: """ The source name, is `None` if the instance is created from an Element or a string. """ return None if self._url is None else os.path.basename(self._url) @property def url(self) -> Optional[str]: """ The source URL, `None` if the instance is created from an Element or a string. """ return self._url @property def base_url(self) -> Optional[str]: """The effective base URL used for completing relative locations.""" return os.path.dirname(self._url) if self._url else self._base_url @property def filepath(self) -> Optional[str]: """ The resource filepath if the instance is created from a local file, `None` otherwise. """ if self._url: url_parts = urlsplit(self._url) if url_parts.scheme in ('', 'file'): return url_parts.path return None @property def allow(self) -> str: """The security mode for accessing resource locations.""" return self._allow @property def defuse(self) -> str: """When to defuse XML data.""" return self._defuse @property def timeout(self) -> int: """The timeout in seconds for accessing remote resources.""" return self._timeout def _access_control(self, url: str) -> None: if self._allow == 'all': return elif self._allow == 'none': raise XMLResourceError("block access to resource {}".format(url)) elif self._allow == 'remote': if is_local_url(url): raise XMLResourceError("block access to local resource {}".format(url)) elif is_remote_url(url): raise XMLResourceError("block access to remote resource {}".format(url)) elif self._allow == 'sandbox' and self._base_url is not None: if not url.startswith(normalize_url(self._base_url)): raise XMLResourceError("block access to out of sandbox file {}".format(url)) def _update_nsmap(self, nsmap: MutableMapping[str, str], prefix: str, uri: str) -> None: if not prefix: if not uri: return elif '' not in nsmap: if self.namespace: nsmap[prefix] = uri return elif nsmap[''] == uri: return prefix = 'default' while prefix in nsmap: if nsmap[prefix] == uri: return match = re.search(r'(\d+)$', prefix) if match: index = int(match.group()) + 1 prefix = prefix[:match.span()[0]] + str(index) else: prefix += '0' nsmap[prefix] = uri def _lazy_iterparse(self, resource: IO[AnyStr], nsmap: Optional[NsmapType] = None) \ -> Iterator[Tuple[str, ElementType]]: events: Tuple[str, ...] _nsmap: List[Tuple[str, str]] if nsmap is None: events = 'start', 'end' _nsmap = [] else: events = 'start-ns', 'end-ns', 'start', 'end' if isinstance(nsmap, list): _nsmap = nsmap _nsmap.clear() else: _nsmap = [] if self._defuse == 'remote' and is_remote_url(self.base_url) \ or self._defuse == 'nonlocal' and not is_local_url(self.base_url) \ or self._defuse == 'always': safe_parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) tree_iterator = PyElementTree.iterparse(resource, events, safe_parser) else: tree_iterator = ElementTree.iterparse(resource, events) root_started = False nsmap_update = False _root = cast(Optional[ElementType], getattr(self, '_root', None)) try: for event, node in tree_iterator: if event == 'start': if not root_started: self._root = node root_started = True if nsmap_update and isinstance(nsmap, dict): for prefix, uri in _nsmap: self._update_nsmap(nsmap, prefix, uri) nsmap_update = False yield event, node elif event == 'end': yield event, node elif nsmap is not None: if event == 'start-ns': _nsmap.append(node) else: _nsmap.pop() nsmap_update = isinstance(nsmap, dict) except Exception as err: if _root is not None: self._root = _root if isinstance(err, PyElementTree.ParseError): raise ElementTree.ParseError(str(err)) from None raise def _parse(self, resource: IO[AnyStr]) -> None: if self._defuse == 'remote' and is_remote_url(self.base_url) \ or self._defuse == 'nonlocal' and not is_local_url(self.base_url) \ or self._defuse == 'always': if not hasattr(resource, 'seekable') or not resource.seekable(): text = resource.read() if isinstance(text, str): resource = StringIO(text) else: resource = BytesIO(text) safe_parser = SafeXMLParser(target=PyElementTree.TreeBuilder()) try: for _ in PyElementTree.iterparse(resource, ('start',), safe_parser): break except PyElementTree.ParseError as err: raise ElementTree.ParseError(str(err)) else: resource.seek(0) elem: Optional[ElementType] = None nsmap: List[Tuple[str, str]] = [] nsmap_changed = False namespaces = {} events = 'start-ns', 'end-ns', 'end' for event, node in ElementTree.iterparse(resource, events): if event == 'end': if nsmap_changed or elem is None: namespaces[node] = nsmap[:] nsmap_changed = False else: namespaces[node] = namespaces[elem] elem = node elif event == 'start-ns': nsmap.append(node) nsmap_changed = True else: nsmap.pop() nsmap_changed = True assert elem is not None self._root = elem self._nsmap = namespaces def _parse_resource(self, resource: IO[AnyStr], url: Optional[str], lazy: Union[bool, int]) -> None: _url, self._url = self._url, url try: if not lazy: self._parse(resource) else: nsmap: List[Tuple[str, str]] = [] for _, root in self._lazy_iterparse(resource, nsmap): # pragma: no cover self._nsmap = {root: nsmap} break except Exception: self._url = _url raise def parse(self, source: XMLSourceType, lazy: Union[bool, int] = False) -> None: if isinstance(lazy, bool): pass elif not isinstance(lazy, int): msg = "invalid type {!r} for the attribute 'lazy'" raise XMLSchemaTypeError(msg.format(type(lazy))) elif lazy < 0: msg = "invalid value {!r} for the attribute 'lazy'" raise XMLSchemaValueError(msg.format(lazy)) url: Optional[str] if isinstance(source, str): if is_url(source): # source is a string containing an URL or a file path url = normalize_url(source, self._base_url) self._access_control(url) with urlopen(url, timeout=self._timeout) as resource: self._parse_resource(resource, url, lazy) self._text = None self._lazy = lazy else: # source is a string containing an XML document resource = StringIO(source) self._parse_resource(resource, None, lazy) self._text = source self._lazy = False elif isinstance(source, bytes): if is_url(source): url = normalize_url(source.decode(), self._base_url) self._access_control(url) with urlopen(url, timeout=self._timeout) as resource: self._parse_resource(resource, url, lazy) self._text = None self._lazy = lazy else: resource = BytesIO(source) self._parse_resource(resource, None, lazy) self._text = source.decode() self._lazy = False elif isinstance(source, Path): url = normalize_url(str(source), self._base_url) self._access_control(url) with urlopen(url, timeout=self._timeout) as resource: self._parse_resource(resource, url, lazy) self._text = None self._lazy = lazy elif isinstance(source, StringIO): self._parse_resource(source, None, lazy) self._text = source.getvalue() self._lazy = lazy elif hasattr(source, 'read'): # source is a readable resource (remote or local file) url = getattr(source, 'url', None) if url is not None: self._access_control(url) # Save remote urls for open new resources (non seekable) if not is_remote_url(url): url = None self._parse_resource(cast(IO[str], source), url, lazy) self._text = None self._lazy = lazy else: # Source is already an Element or an ElementTree. if hasattr(source, 'tag') and hasattr(source, 'attrib'): # Source is already an Element --> nothing to parse self._root = cast(ElementType, source) elif is_etree_document(source): # Could be only an ElementTree object at last self._root = cast(ElementTreeType, source).getroot() else: raise XMLSchemaTypeError( "wrong type %r for 'source' attribute: an ElementTree object or " "an Element instance or a string containing XML data or an URL " "or a file-like object is required." % type(source) ) self._text = self._url = None self._lazy = False self._nsmap = {} # TODO for Python 3.8+: need a Protocol for checking this with isinstance() if hasattr(self._root, 'nsmap'): nsmap = [] lxml_nsmap = None for elem in cast(Any, self._root.iter()): if lxml_nsmap != elem.nsmap: lxml_nsmap = elem.nsmap nsmap = [(k or '', v) for k, v in elem.nsmap.items()] self._nsmap[elem] = nsmap self._parent_map = None self._source = source @property def namespace(self) -> str: """The namespace of the XML resource.""" return '' if self._root is None else get_namespace(self._root.tag) @property def parent_map(self) -> Dict[ElementType, Optional[ElementType]]: if self._lazy: raise XMLResourceError("cannot create the parent map of a lazy resource") if self._parent_map is None: assert self._root is not None self._parent_map = {child: elem for elem in self._root.iter() for child in elem} self._parent_map[self._root] = None return self._parent_map def get_nsmap(self, elem: ElementType) -> List[Tuple[str, str]]: """ Returns a list of couples with the namespace (nsmap) map of the element. Lazy resources have only a nsmap for the root element. If no nsmap is found for the element returns an empty list. """ try: return self._nsmap[elem] except KeyError: return [] def get_absolute_path(self, path: Optional[str] = None) -> str: if path is None: if self._lazy: return '/%s/%s' % (self._root.tag, '/'.join('*' * int(self._lazy))) return '/%s' % self._root.tag elif path.startswith('/'): return path else: return '/%s/%s' % (self._root.tag, path) def get_text(self) -> str: """ Gets the source text of the XML document. If the source text is not available creates an encoded string representation of the XML tree. Il the resource is lazy raises a resource error. """ if self._text is not None: return self._text elif self._url is not None: self.load() if self._text is not None: return self._text return self.tostring(xml_declaration=True) def tostring(self, indent: str = '', max_lines: Optional[int] = None, spaces_for_tab: int = 4, xml_declaration: bool = False) -> str: """Generates a string representation of the XML resource.""" if self._lazy: raise XMLResourceError("cannot serialize a lazy resource") elem = self._root namespaces = self.get_namespaces(root_only=False) _string = etree_tostring(elem, namespaces, indent, max_lines, spaces_for_tab, xml_declaration) return _string.decode('utf-8') if isinstance(_string, bytes) else _string def subresource(self, elem: ElementType) -> 'XMLResource': """Create an XMLResource instance from a subelement of a non-lazy XML tree.""" if self._lazy: raise XMLResourceError("cannot create a subresource from a lazy resource") for e in self._root.iter(): # pragma: no cover if e is elem: break else: msg = "{!r} is not an element or the XML resource tree" raise XMLResourceError(msg.format(elem)) resource = XMLResource(elem, self.base_url, self._allow, self._defuse, self._timeout) if not hasattr(elem, 'nsmap') and self._nsmap is not None: namespaces = {} _nsmap = self._nsmap[elem] _nsmap_initial_len = len(_nsmap) nsmap = list(dict(_nsmap).items()) for e in elem.iter(): if _nsmap is not self._nsmap[e]: _nsmap = self._nsmap[e] nsmap = nsmap[:] nsmap.extend(_nsmap[_nsmap_initial_len:]) namespaces[e] = nsmap resource._nsmap = namespaces return resource def open(self) -> IO[AnyStr]: """ Returns a opened resource reader object for the instance URL. If the source attribute is a seekable file-like object rewind the source and return it. """ if self.seek(0) == 0: return cast(IO[AnyStr], self._source) elif self._url is None: raise XMLResourceError("can't open, the resource has no URL associated.") try: return cast(IO[AnyStr], urlopen(self._url, timeout=self._timeout)) except URLError as err: raise XMLResourceError( "cannot access to resource %r: %s" % (self._url, err.reason) ) def seek(self, position: int) -> Optional[int]: """ Change stream position if the XML resource was created with a seekable file-like object. In the other cases this method has no effect. """ if not hasattr(self._source, 'read'): return None try: if not self._source.seekable(): # type: ignore[union-attr] return None except AttributeError: return None # pragma: no cover except ValueError as err: raise XMLResourceError(str(err)) from None else: return self._source.seek(position) # type: ignore[union-attr] def close(self) -> None: """ Close the XML resource if it's created with a file-like object. In other cases this method has no effect. """ try: self._source.close() # type: ignore[union-attr] except (AttributeError, TypeError): pass def load(self) -> None: """ Loads the XML text from the data source. If the data source is an Element the source XML text can't be retrieved. """ if self._url is None and not hasattr(self._source, 'read'): return # Created from Element or text source --> already loaded elif self._lazy: raise XMLResourceError("cannot load a lazy resource") resource = self.open() try: data = resource.read() finally: # We don't want to close the file obj if it wasn't originally # opened by `XMLResource`. That is the concern of the code # where the file obj came from. if resource is not self._source: resource.close() if isinstance(data, bytes): try: text = data.decode('utf-8') except UnicodeDecodeError: text = data.decode('iso-8859-1') else: text = data self._text = text def is_lazy(self) -> bool: """Returns `True` if the XML resource is lazy.""" return bool(self._lazy) def is_remote(self) -> bool: """Returns `True` if the resource is related with remote XML data.""" return is_remote_url(self._url) def is_local(self) -> bool: """Returns `True` if the resource is related with local XML data.""" return is_local_url(self._url) @property def lazy_depth(self) -> int: """ The optimal depth for validate this resource. Is a positive integer for lazy resources and 0 for fully loaded XML trees. """ return int(self._lazy) def is_loaded(self) -> bool: """Returns `True` if the XML text of the data source is loaded.""" return self._text is not None def iter(self, tag: Optional[str] = None, nsmap: Optional[NsmapType] = None) \ -> Iterator[ElementType]: """ XML resource tree iterator. The iteration of a lazy resource is in reverse order (top level element is the last). If tag is not None or '*', only elements whose tag equals tag are returned from the iterator. Provide a *nsmap* list for tracking the namespaces of yielded elements. If *nsmap* is a dictionary the tracking of namespaces is cumulative on the whole tree, renaming prefixes in case of conflicts. """ if self._lazy: resource = self.open() tag = '*' if tag is None else tag.strip() try: for event, node in self._lazy_iterparse(resource, nsmap): if event == 'end': if tag == '*' or node.tag == tag: yield node node.clear() finally: # Close the resource only if it was originally opened by XMLResource if resource is not self._source: resource.close() elif not self._nsmap or nsmap is None: yield from self._root.iter(tag) else: _nsmap = None for elem in self._root.iter(tag): try: if _nsmap is not self._nsmap[elem]: _nsmap = self._nsmap[elem] if isinstance(nsmap, list): nsmap.clear() nsmap.extend(_nsmap) else: for prefix, uri in _nsmap: self._update_nsmap(nsmap, prefix, uri) except KeyError: pass yield elem def iter_location_hints(self, tag: Optional[str] = None) -> Iterator[Tuple[str, str]]: """ Yields all schema location hints of the XML resource. If tag is not None or '*', only location hints of elements whose tag equals tag are returned from the iterator. """ for elem in self.iter(tag): yield from etree_iter_location_hints(elem) def iter_depth(self, mode: int = 1, nsmap: Optional[NsmapType] = None, ancestors: Optional[List[ElementType]] = None) -> Iterator[ElementType]: """ Iterates XML subtrees. For fully loaded resources yields the root element. On lazy resources the argument *mode* can change the sequence and the completeness of yielded elements. There are four possible modes, that generate different sequences of elements:\n 1. Only the elements at *depth_level* level of the tree\n 2. Only a root element pruned at *depth_level*\n 3. The elements at *depth_level* and then a pruned root\n 4. An incomplete root at start, the elements at *depth_level* and a pruned root :param mode: an integer in range [1..4] that defines the iteration mode. :param nsmap: provide a list/dict for tracking the namespaces of yielded \ elements. If a list is passed the tracking is done at element level, otherwise \ the tracking is on the whole tree, renaming prefixes in case of conflicts. :param ancestors: provide a list for tracking the ancestors of yielded elements. """ if ancestors is not None: ancestors.clear() if not self._lazy: if nsmap is not None and self._nsmap: if isinstance(nsmap, list): nsmap.clear() nsmap.extend(self._nsmap[self._root]) else: for elem in self._root.iter(): for prefix, uri in self._nsmap[elem]: self._update_nsmap(nsmap, prefix, uri) yield self._root return if mode not in (1, 2, 3, 4): raise XMLSchemaValueError("invalid argument mode={!r}".format(mode)) resource = self.open() level = 0 subtree_level = int(self._lazy) try: for event, node in self._lazy_iterparse(resource, nsmap): if event == "start": if not level: if mode == 4: yield node if ancestors is not None and level < subtree_level: ancestors.append(node) level += 1 else: level -= 1 if not level: if mode != 1: yield node elif level != subtree_level: if ancestors is not None and level < subtree_level: ancestors.pop() continue # pragma: no cover elif mode != 2: yield node del node[:] # delete children, keep attributes, text and tail. finally: if self._source is not resource: resource.close() def iterfind(self, path: str, namespaces: Optional[NamespacesType] = None, nsmap: Optional[NsmapType] = None, ancestors: Optional[List[ElementType]] = None) -> Iterator[ElementType]: """ Apply XPath selection to XML resource that yields full subtrees. :param path: an XPath expression to select element nodes. :param namespaces: an optional mapping from namespace prefixes to URIs \ used for parsing the XPath expression. :param nsmap: provide a list/dict for tracking the namespaces of yielded \ elements. If a list is passed the tracking is done at element level, otherwise \ the tracking is on the whole tree, renaming prefixes in case of conflicts. :param ancestors: provide a list for tracking the ancestors of yielded elements. """ selector: Any if self._lazy: selector = LazySelector(path, namespaces) path = path.replace(' ', '').replace('./', '') resource = self.open() level = 0 select_all = '*' in path and set(path).issubset({'*', '/'}) if path == '.': subtree_level = 0 elif path.startswith('/'): subtree_level = path.count('/') - 1 else: subtree_level = path.count('/') + 1 try: for event, node in self._lazy_iterparse(resource, nsmap): if event == "start": if ancestors is not None and level < subtree_level: ancestors.append(node) level += 1 else: level -= 1 if not level: if subtree_level: pass elif select_all or node in selector.select(self._root): yield node elif not subtree_level: continue elif level != subtree_level: if ancestors is not None and level < subtree_level: ancestors.pop() continue # pragma: no cover elif select_all or node in selector.select(self._root): yield node del node[:] # delete children, keep attributes, text and tail. finally: if self._source is not resource: resource.close() else: if ancestors is None: selector = iter_select else: parent_map = self.parent_map ancestors.clear() def selector(*args: Any, **kwargs: Any) -> Iterator[Any]: assert ancestors is not None for e in iter_select(*args, **kwargs): if e is self._root: ancestors.clear() else: _ancestors = [] parent = e try: while True: parent = parent_map[parent] if parent is not None: _ancestors.append(parent) except KeyError: pass if _ancestors: ancestors.clear() ancestors.extend(reversed(_ancestors)) yield e if not self._nsmap or nsmap is None: yield from selector(self._root, path, namespaces, strict=False) else: _nsmap = None for elem in selector(self._root, path, namespaces, strict=False): try: if _nsmap is not self._nsmap[elem]: _nsmap = self._nsmap[elem] if isinstance(nsmap, list): nsmap.clear() nsmap.extend(_nsmap) else: for prefix, uri in _nsmap: self._update_nsmap(nsmap, prefix, uri) except KeyError: pass yield elem def find(self, path: str, namespaces: Optional[NamespacesType] = None, nsmap: Optional[NsmapType] = None, ancestors: Optional[List[ElementType]] = None) -> Optional[ElementType]: return next(self.iterfind(path, namespaces, nsmap, ancestors), None) def findall(self, path: str, namespaces: Optional[NamespacesType] = None) \ -> List[ElementType]: return list(self.iterfind(path, namespaces)) def get_namespaces(self, namespaces: Optional[NamespacesType] = None, root_only: Optional[bool] = None) -> NamespacesType: """ Extracts namespaces with related prefixes from the XML resource. If a duplicate prefix declaration is encountered and the prefix maps a different namespace, adds the namespace using a different generated prefix. The empty prefix '' is used only if it's declared at root level to avoid erroneous mapping of local names. In other cases uses 'default' prefix as substitute. :param namespaces: builds the namespace map starting over the dictionary provided. :param root_only: if `True`, or `None` and the resource is lazy, extracts \ only the namespaces declared in the root element. :return: a dictionary for mapping namespace prefixes to full URI. """ if namespaces is None: namespaces = {} elif namespaces.get('xml', XML_NAMESPACE) != XML_NAMESPACE: msg = "reserved prefix (xml) must not be bound to another namespace name" raise XMLSchemaValueError(msg) else: namespaces = copy.copy(namespaces) try: if root_only or root_only is None and self._lazy: for _ in self.iter(nsmap=namespaces): break else: for _ in self.iter(nsmap=namespaces): pass except (ElementTree.ParseError, PyElementTree.ParseError, UnicodeEncodeError): pass return namespaces def get_locations(self, locations: Optional[LocationsType] = None, root_only: Optional[bool] = None) -> NormalizedLocationsType: """ Extracts a list of schema location hints from the XML resource. The locations are normalized using the base URL of the instance. :param locations: a sequence of schema location hints inserted \ before the ones extracted from the XML resource. Locations passed \ within a tuple container are not normalized. :param root_only: if `True`, or if `None` and the resource is lazy, \ extracts the location hints of the root element only. :returns: a list of couples containing normalized location hints. """ if root_only is None: root_only = bool(self._lazy) if not locations: location_hints = [] elif isinstance(locations, tuple): location_hints = [x for x in locations] else: location_hints = normalize_locations(locations, self.base_url) if root_only: location_hints.extend([ (ns, normalize_url(url, self.base_url)) for ns, url in etree_iter_location_hints(self._root) ]) else: location_hints.extend([ (ns, normalize_url(url, self.base_url)) for ns, url in self.iter_location_hints() ]) return location_hints �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017155�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/HFP/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017572�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/HFP/XMLSchema-hasFacetAndProperty_minimal.xsd��������������������0000664�0000000�0000000�00000002776�14211403446�0027521�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty" xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"> <!-- A minimal schema that not requires the loading of xhtml namespace --> <element name="hasFacet"> <complexType> <attribute name="name" use="required"> <simpleType> <restriction base="NMTOKEN"> <enumeration value="length"/> <enumeration value="minLength"/> <enumeration value="maxLength"/> <enumeration value="pattern"/> <enumeration value="enumeration"/> <enumeration value="maxInclusive"/> <enumeration value="maxExclusive"/> <enumeration value="minInclusive"/> <enumeration value="minExclusive"/> <enumeration value="totalDigits"/> <enumeration value="fractionDigits"/> <enumeration value="whiteSpace"/> <enumeration value="maxScale"/> <enumeration value="minScale"/> </restriction> </simpleType> </attribute> </complexType> </element> <element name="hasProperty"> <complexType> <attribute name="name" use="required"> <simpleType> <restriction base="NMTOKEN"> <enumeration value="ordered"/> <enumeration value="bounded"/> <enumeration value="cardinality"/> <enumeration value="numeric"/> </restriction> </simpleType> </attribute> <attribute name="value" type="normalizedString" use="required"/> </complexType> </element> </schema> ��xmlschema-1.10.0/xmlschema/schemas/VC/��������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017465�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/VC/XMLSchema-versioning.xsd��������������������������������������0000664�0000000�0000000�00000001730�14211403446�0024150�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/2007/XMLSchema-versioning"> <!-- A schema for XMLSchema-versioning namespace that includes all the attributes defined in XSD 1.1 normative document https://www.w3.org/TR/xmlschema11-1/ --> <xs:attribute name="minVersion" type="xs:decimal" /> <xs:attribute name="maxVersion" type="xs:decimal" /> <xs:attribute name="typeAvailable"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> <xs:attribute name="typeUnavailable"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> <xs:attribute name="facetAvailable"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> <xs:attribute name="facetUnavailable"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> </xs:schema> ����������������������������������������xmlschema-1.10.0/xmlschema/schemas/WSDL/������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017726�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/WSDL/soap-encoding.xsd�������������������������������������������0000664�0000000�0000000�00000045404�14211403446�0023203�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='UTF-8' ?> <!-- Schema for the SOAP/1.1 encoding Portions © 2001 DevelopMentor. © 2001 W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. This document is governed by the W3C Software License [1] as described in the FAQ [2]. [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720 [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. 2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © 2001 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/" 3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) Original W3C files; http://www.w3.org/2001/06/soap-encoding Changes made: - reverted namespace to http://schemas.xmlsoap.org/soap/encoding/ - reverted root to only allow 0 and 1 as lexical values - removed default value from root attribute declaration THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://schemas.xmlsoap.org/soap/encoding/" > <xs:attribute name="root" > <xs:annotation> <xs:documentation> 'root' can be used to distinguish serialization roots from other elements that are present in a serialization but are not roots of a serialized value graph </xs:documentation> </xs:annotation> <xs:simpleType> <xs:restriction base='xs:boolean'> <xs:pattern value='0|1' /> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attributeGroup name="commonAttributes" > <xs:annotation> <xs:documentation> Attributes common to all elements that function as accessors or represent independent (multi-ref) values. The href attribute is intended to be used in a manner like CONREF. That is, the element content should be empty iff the href attribute appears </xs:documentation> </xs:annotation> <xs:attribute name="id" type="xs:ID" /> <xs:attribute name="href" type="xs:anyURI" /> <xs:anyAttribute namespace="##other" processContents="lax" /> </xs:attributeGroup> <!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. --> <!-- Array attributes. Needed to give the type and dimensions of an array's contents, and the offset for partially-transmitted arrays. --> <xs:simpleType name="arrayCoordinate" > <xs:restriction base="xs:string" /> </xs:simpleType> <xs:attribute name="arrayType" type="xs:string" /> <xs:attribute name="offset" type="tns:arrayCoordinate" /> <xs:attributeGroup name="arrayAttributes" > <xs:attribute ref="tns:arrayType" /> <xs:attribute ref="tns:offset" /> </xs:attributeGroup> <xs:attribute name="position" type="tns:arrayCoordinate" /> <xs:attributeGroup name="arrayMemberAttributes" > <xs:attribute ref="tns:position" /> </xs:attributeGroup> <xs:group name="Array" > <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> </xs:group> <xs:element name="Array" type="tns:Array" /> <xs:complexType name="Array" > <xs:annotation> <xs:documentation> 'Array' is a complex type for accessors identified by position </xs:documentation> </xs:annotation> <xs:group ref="tns:Array" minOccurs="0" /> <xs:attributeGroup ref="tns:arrayAttributes" /> <xs:attributeGroup ref="tns:commonAttributes" /> </xs:complexType> <!-- 'Struct' is a complex type for accessors identified by name. Constraint: No element may be have the same name as any other, nor may any element have a maxOccurs > 1. --> <xs:element name="Struct" type="tns:Struct" /> <xs:group name="Struct" > <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> </xs:group> <xs:complexType name="Struct" > <xs:group ref="tns:Struct" minOccurs="0" /> <xs:attributeGroup ref="tns:commonAttributes"/> </xs:complexType> <!-- 'Base64' can be used to serialize binary data using base64 encoding as defined in RFC2045 but without the MIME line length limitation. --> <xs:simpleType name="base64" > <xs:restriction base="xs:base64Binary" /> </xs:simpleType> <!-- Element declarations corresponding to each of the simple types in the XML Schemas Specification. --> <xs:element name="duration" type="tns:duration" /> <xs:complexType name="duration" > <xs:simpleContent> <xs:extension base="xs:duration" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="dateTime" type="tns:dateTime" /> <xs:complexType name="dateTime" > <xs:simpleContent> <xs:extension base="xs:dateTime" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="NOTATION" type="tns:NOTATION" /> <xs:complexType name="NOTATION" > <xs:simpleContent> <xs:extension base="xs:QName" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="time" type="tns:time" /> <xs:complexType name="time" > <xs:simpleContent> <xs:extension base="xs:time" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="date" type="tns:date" /> <xs:complexType name="date" > <xs:simpleContent> <xs:extension base="xs:date" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="gYearMonth" type="tns:gYearMonth" /> <xs:complexType name="gYearMonth" > <xs:simpleContent> <xs:extension base="xs:gYearMonth" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="gYear" type="tns:gYear" /> <xs:complexType name="gYear" > <xs:simpleContent> <xs:extension base="xs:gYear" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="gMonthDay" type="tns:gMonthDay" /> <xs:complexType name="gMonthDay" > <xs:simpleContent> <xs:extension base="xs:gMonthDay" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="gDay" type="tns:gDay" /> <xs:complexType name="gDay" > <xs:simpleContent> <xs:extension base="xs:gDay" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="gMonth" type="tns:gMonth" /> <xs:complexType name="gMonth" > <xs:simpleContent> <xs:extension base="xs:gMonth" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="boolean" type="tns:boolean" /> <xs:complexType name="boolean" > <xs:simpleContent> <xs:extension base="xs:boolean" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="base64Binary" type="tns:base64Binary" /> <xs:complexType name="base64Binary" > <xs:simpleContent> <xs:extension base="xs:base64Binary" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="hexBinary" type="tns:hexBinary" /> <xs:complexType name="hexBinary" > <xs:simpleContent> <xs:extension base="xs:hexBinary" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="float" type="tns:float" /> <xs:complexType name="float" > <xs:simpleContent> <xs:extension base="xs:float" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="double" type="tns:double" /> <xs:complexType name="double" > <xs:simpleContent> <xs:extension base="xs:double" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="anyURI" type="tns:anyURI" /> <xs:complexType name="anyURI" > <xs:simpleContent> <xs:extension base="xs:anyURI" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="QName" type="tns:QName" /> <xs:complexType name="QName" > <xs:simpleContent> <xs:extension base="xs:QName" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="string" type="tns:string" /> <xs:complexType name="string" > <xs:simpleContent> <xs:extension base="xs:string" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="normalizedString" type="tns:normalizedString" /> <xs:complexType name="normalizedString" > <xs:simpleContent> <xs:extension base="xs:normalizedString" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="token" type="tns:token" /> <xs:complexType name="token" > <xs:simpleContent> <xs:extension base="xs:token" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="language" type="tns:language" /> <xs:complexType name="language" > <xs:simpleContent> <xs:extension base="xs:language" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="Name" type="tns:Name" /> <xs:complexType name="Name" > <xs:simpleContent> <xs:extension base="xs:Name" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="NMTOKEN" type="tns:NMTOKEN" /> <xs:complexType name="NMTOKEN" > <xs:simpleContent> <xs:extension base="xs:NMTOKEN" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="NCName" type="tns:NCName" /> <xs:complexType name="NCName" > <xs:simpleContent> <xs:extension base="xs:NCName" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="NMTOKENS" type="tns:NMTOKENS" /> <xs:complexType name="NMTOKENS" > <xs:simpleContent> <xs:extension base="xs:NMTOKENS" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="ID" type="tns:ID" /> <xs:complexType name="ID" > <xs:simpleContent> <xs:extension base="xs:ID" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="IDREF" type="tns:IDREF" /> <xs:complexType name="IDREF" > <xs:simpleContent> <xs:extension base="xs:IDREF" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="ENTITY" type="tns:ENTITY" /> <xs:complexType name="ENTITY" > <xs:simpleContent> <xs:extension base="xs:ENTITY" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="IDREFS" type="tns:IDREFS" /> <xs:complexType name="IDREFS" > <xs:simpleContent> <xs:extension base="xs:IDREFS" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="ENTITIES" type="tns:ENTITIES" /> <xs:complexType name="ENTITIES" > <xs:simpleContent> <xs:extension base="xs:ENTITIES" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="decimal" type="tns:decimal" /> <xs:complexType name="decimal" > <xs:simpleContent> <xs:extension base="xs:decimal" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="integer" type="tns:integer" /> <xs:complexType name="integer" > <xs:simpleContent> <xs:extension base="xs:integer" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="nonPositiveInteger" type="tns:nonPositiveInteger" /> <xs:complexType name="nonPositiveInteger" > <xs:simpleContent> <xs:extension base="xs:nonPositiveInteger" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="negativeInteger" type="tns:negativeInteger" /> <xs:complexType name="negativeInteger" > <xs:simpleContent> <xs:extension base="xs:negativeInteger" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="long" type="tns:long" /> <xs:complexType name="long" > <xs:simpleContent> <xs:extension base="xs:long" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="int" type="tns:int" /> <xs:complexType name="int" > <xs:simpleContent> <xs:extension base="xs:int" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="short" type="tns:short" /> <xs:complexType name="short" > <xs:simpleContent> <xs:extension base="xs:short" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="byte" type="tns:byte" /> <xs:complexType name="byte" > <xs:simpleContent> <xs:extension base="xs:byte" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="nonNegativeInteger" type="tns:nonNegativeInteger" /> <xs:complexType name="nonNegativeInteger" > <xs:simpleContent> <xs:extension base="xs:nonNegativeInteger" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="unsignedLong" type="tns:unsignedLong" /> <xs:complexType name="unsignedLong" > <xs:simpleContent> <xs:extension base="xs:unsignedLong" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="unsignedInt" type="tns:unsignedInt" /> <xs:complexType name="unsignedInt" > <xs:simpleContent> <xs:extension base="xs:unsignedInt" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="unsignedShort" type="tns:unsignedShort" /> <xs:complexType name="unsignedShort" > <xs:simpleContent> <xs:extension base="xs:unsignedShort" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="unsignedByte" type="tns:unsignedByte" /> <xs:complexType name="unsignedByte" > <xs:simpleContent> <xs:extension base="xs:unsignedByte" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="positiveInteger" type="tns:positiveInteger" /> <xs:complexType name="positiveInteger" > <xs:simpleContent> <xs:extension base="xs:positiveInteger" > <xs:attributeGroup ref="tns:commonAttributes" /> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="anyType" /> </xs:schema> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/WSDL/soap-envelope.xsd�������������������������������������������0000664�0000000�0000000�00000013655�14211403446�0023235�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Schema for the SOAP/1.1 envelope Portions © 2001 DevelopMentor. © 2001 W3C (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. This document is governed by the W3C Software License [1] as described in the FAQ [2]. [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720 [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions: Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make: 1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. 2. Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, a short notice of the following form (hypertext is preferred, text is permitted) should be used within the body of any redistributed or derivative code: "Copyright © 2001 World Wide Web Consortium, (Massachusetts Institute of Technology, Institut National de Recherche en Informatique et en Automatique, Keio University). All Rights Reserved. http://www.w3.org/Consortium/Legal/" 3. Notice of any changes or modifications to the W3C files, including the date changes were made. (We recommend you provide URIs to the location from which the code is derived.) Original W3C files; http://www.w3.org/2001/06/soap-envelope Changes made: - reverted namespace to http://schemas.xmlsoap.org/soap/envelope/ - reverted mustUnderstand to only allow 0 and 1 as lexical values - made encodingStyle a global attribute 20020825 - removed default value from mustUnderstand attribute declaration THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION. The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the software without specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/" targetNamespace="http://schemas.xmlsoap.org/soap/envelope/"> <!-- Envelope, header and body --> <xs:element name="Envelope" type="tns:Envelope"/> <xs:complexType name="Envelope"> <xs:sequence> <xs:element ref="tns:Header" minOccurs="0"/> <xs:element ref="tns:Body" minOccurs="1"/> <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> <xs:element name="Header" type="tns:Header"/> <xs:complexType name="Header"> <xs:sequence> <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> <xs:element name="Body" type="tns:Body"/> <xs:complexType name="Body"> <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="lax"> <xs:annotation> <xs:documentation> Prose in the spec does not specify that attributes are allowed on the Body element </xs:documentation> </xs:annotation> </xs:anyAttribute> </xs:complexType> <!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. --> <xs:attribute name="mustUnderstand"> <xs:simpleType> <xs:restriction base="xs:boolean"> <xs:pattern value="0|1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="actor" type="xs:anyURI"/> <xs:simpleType name="encodingStyle"> <xs:annotation> <xs:documentation> 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification </xs:documentation> </xs:annotation> <xs:list itemType="xs:anyURI"/> </xs:simpleType> <xs:attribute name="encodingStyle" type="tns:encodingStyle"/> <xs:attributeGroup name="encodingStyle"> <xs:attribute ref="tns:encodingStyle"/> </xs:attributeGroup> <xs:element name="Fault" type="tns:Fault"/> <xs:complexType name="Fault" final="extension"> <xs:annotation> <xs:documentation> Fault reporting structure </xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="faultcode" type="xs:QName"/> <xs:element name="faultstring" type="xs:string"/> <xs:element name="faultactor" type="xs:anyURI" minOccurs="0"/> <xs:element name="detail" type="tns:detail" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="detail"> <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="lax"/> </xs:complexType> </xs:schema>�����������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/WSDL/wsdl-soap.xsd�����������������������������������������������0000664�0000000�0000000�00000013565�14211403446�0022371�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright 2001 - 2005, International Business Machines Corporation and Microsoft Corporation All Rights Reserved License for WSDL Schema Files The Authors grant permission to copy and distribute the WSDL Schema Files in any medium without fee or royalty as long as this notice and license are distributed with them. The originals of these files can be located at: http://schemas.xmlsoap.org/wsdl/soap/2003-02-11.xsd THESE SCHEMA FILES ARE PROVIDED "AS IS," AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THESE FILES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT OR TITLE. THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY USE OR DISTRIBUTION OF THESE FILES. The name and trademarks of the Authors may NOT be used in any manner, including advertising or publicity pertaining to these files or any program or service that uses these files, written prior permission. Title to copyright in these files will at all times remain with the Authors. No other rights are granted by implication, estoppel or otherwise. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://schemas.xmlsoap.org/wsdl/soap/" > <xs:import namespace = "http://schemas.xmlsoap.org/wsdl/" /> <xs:simpleType name="encodingStyle" > <xs:annotation> <xs:documentation> "encodingStyle" indicates any canonicalization conventions followed in the contents of the containing element. For example, the value "http://schemas.xmlsoap.org/soap/encoding/" indicates the pattern described in SOAP specification </xs:documentation> </xs:annotation> <xs:list itemType="xs:anyURI" /> </xs:simpleType> <xs:element name="binding" type="soap:tBinding" /> <xs:complexType name="tBinding" > <xs:complexContent> <xs:extension base="wsdl:tExtensibilityElement" > <xs:attribute name="transport" type="xs:anyURI" use="required" /> <xs:attribute name="style" type="soap:tStyleChoice" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:simpleType name="tStyleChoice" > <xs:restriction base="xs:string" > <xs:enumeration value="rpc" /> <xs:enumeration value="document" /> </xs:restriction> </xs:simpleType> <xs:element name="operation" type="soap:tOperation" /> <xs:complexType name="tOperation" > <xs:complexContent> <xs:extension base="wsdl:tExtensibilityElement" > <xs:attribute name="soapAction" type="xs:anyURI" use="optional" /> <xs:attribute name="style" type="soap:tStyleChoice" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="body" type="soap:tBody" /> <xs:attributeGroup name="tBodyAttributes" > <xs:attribute name="encodingStyle" type="soap:encodingStyle" use="optional" /> <xs:attribute name="use" type="soap:useChoice" use="optional" /> <xs:attribute name="namespace" type="xs:anyURI" use="optional" /> </xs:attributeGroup> <xs:complexType name="tBody" > <xs:complexContent> <xs:extension base="wsdl:tExtensibilityElement" > <xs:attribute name="parts" type="xs:NMTOKENS" use="optional" /> <xs:attributeGroup ref = "soap:tBodyAttributes" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:simpleType name="useChoice" > <xs:restriction base="xs:string" > <xs:enumeration value="literal" /> <xs:enumeration value="encoded" /> </xs:restriction> </xs:simpleType> <xs:element name="fault" type="soap:tFault" /> <xs:complexType name="tFaultRes" abstract="true" > <xs:complexContent> <xs:restriction base="soap:tBody" > <xs:attribute ref="wsdl:required" use="optional" /> <xs:attribute name="parts" type="xs:NMTOKENS" use="prohibited" /> <xs:attributeGroup ref="soap:tBodyAttributes" /> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="tFault" > <xs:complexContent> <xs:extension base="soap:tFaultRes"> <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="header" type="soap:tHeader" /> <xs:attributeGroup name="tHeaderAttributes" > <xs:attribute name="message" type="xs:QName" use="required" /> <xs:attribute name="part" type="xs:NMTOKEN" use="required" /> <xs:attribute name="use" type="soap:useChoice" use="required" /> <xs:attribute name="encodingStyle" type="soap:encodingStyle" use="optional" /> <xs:attribute name="namespace" type="xs:anyURI" use="optional" /> </xs:attributeGroup> <xs:complexType name="tHeader" > <xs:complexContent> <xs:extension base="wsdl:tExtensibilityElement" > <xs:sequence> <xs:element ref="soap:headerfault" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attributeGroup ref="soap:tHeaderAttributes" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="headerfault" type="soap:tHeaderFault" /> <xs:complexType name="tHeaderFault" > <xs:attributeGroup ref="soap:tHeaderAttributes" /> </xs:complexType> <xs:element name="address" type="soap:tAddress" /> <xs:complexType name="tAddress" > <xs:complexContent> <xs:extension base="wsdl:tExtensibilityElement" > <xs:attribute name="location" type="xs:anyURI" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> </xs:schema>�������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/WSDL/wsdl.xsd����������������������������������������������������0000664�0000000�0000000�00000027174�14211403446�0021432�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright 2001 - 2005, International Business Machines Corporation and Microsoft Corporation All Rights Reserved License for WSDL Schema Files The Authors grant permission to copy and distribute the WSDL Schema Files in any medium without fee or royalty as long as this notice and license are distributed with them. The originals of these files can be located at: http://schemas.xmlsoap.org/wsdl/2003-02-11.xsd THESE SCHEMA FILES ARE PROVIDED "AS IS," AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THESE FILES, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT OR TITLE. THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY USE OR DISTRIBUTION OF THESE FILES. The name and trademarks of the Authors may NOT be used in any manner, including advertising or publicity pertaining to these files or any program or service that uses these files, written prior permission. Title to copyright in these files will at all times remain with the Authors. No other rights are granted by implication, estoppel or otherwise. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://schemas.xmlsoap.org/wsdl/" elementFormDefault="qualified" > <xs:complexType mixed="true" name="tDocumentation" > <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> </xs:complexType> <xs:complexType name="tDocumented" > <xs:annotation> <xs:documentation> This type is extended by component types to allow them to be documented </xs:documentation> </xs:annotation> <xs:sequence> <xs:element name="documentation" type="wsdl:tDocumentation" minOccurs="0" /> </xs:sequence> </xs:complexType> <xs:complexType name="tExtensibleAttributesDocumented" abstract="true" > <xs:complexContent> <xs:extension base="wsdl:tDocumented" > <xs:annotation> <xs:documentation> This type is extended by component types to allow attributes from other namespaces to be added. </xs:documentation> </xs:annotation> <xs:anyAttribute namespace="##other" processContents="lax" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tExtensibleDocumented" abstract="true" > <xs:complexContent> <xs:extension base="wsdl:tDocumented" > <xs:annotation> <xs:documentation> This type is extended by component types to allow elements from other namespaces to be added. </xs:documentation> </xs:annotation> <xs:sequence> <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="definitions" type="wsdl:tDefinitions" > <xs:key name="message" > <xs:selector xpath="wsdl:message" /> <xs:field xpath="@name" /> </xs:key> <xs:key name="portType" > <xs:selector xpath="wsdl:portType" /> <xs:field xpath="@name" /> </xs:key> <xs:key name="binding" > <xs:selector xpath="wsdl:binding" /> <xs:field xpath="@name" /> </xs:key> <xs:key name="service" > <xs:selector xpath="wsdl:service" /> <xs:field xpath="@name" /> </xs:key> <xs:key name="import" > <xs:selector xpath="wsdl:import" /> <xs:field xpath="@namespace" /> </xs:key> </xs:element> <xs:group name="anyTopLevelOptionalElement" > <xs:annotation> <xs:documentation> Any top level optional element allowed to appear more then once - any child of definitions element except wsdl:types. Any extensibility element is allowed in any place. </xs:documentation> </xs:annotation> <xs:choice> <xs:element name="import" type="wsdl:tImport" /> <xs:element name="types" type="wsdl:tTypes" /> <xs:element name="message" type="wsdl:tMessage" > <xs:unique name="part" > <xs:selector xpath="wsdl:part" /> <xs:field xpath="@name" /> </xs:unique> </xs:element> <xs:element name="portType" type="wsdl:tPortType" /> <xs:element name="binding" type="wsdl:tBinding" /> <xs:element name="service" type="wsdl:tService" > <xs:unique name="port" > <xs:selector xpath="wsdl:port" /> <xs:field xpath="@name" /> </xs:unique> </xs:element> </xs:choice> </xs:group> <xs:complexType name="tDefinitions" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:group ref="wsdl:anyTopLevelOptionalElement" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="targetNamespace" type="xs:anyURI" use="optional" /> <xs:attribute name="name" type="xs:NCName" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tImport" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleAttributesDocumented" > <xs:attribute name="namespace" type="xs:anyURI" use="required" /> <xs:attribute name="location" type="xs:anyURI" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tTypes" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" /> </xs:complexContent> </xs:complexType> <xs:complexType name="tMessage" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:element name="part" type="wsdl:tPart" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tPart" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleAttributesDocumented" > <xs:attribute name="name" type="xs:NCName" use="required" /> <xs:attribute name="element" type="xs:QName" use="optional" /> <xs:attribute name="type" type="xs:QName" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tPortType" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleAttributesDocumented" > <xs:sequence> <xs:element name="operation" type="wsdl:tOperation" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tOperation" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:choice> <xs:group ref="wsdl:request-response-or-one-way-operation" /> <xs:group ref="wsdl:solicit-response-or-notification-operation" /> </xs:choice> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> <xs:attribute name="parameterOrder" type="xs:NMTOKENS" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="request-response-or-one-way-operation" > <xs:sequence> <xs:element name="input" type="wsdl:tParam" /> <xs:sequence minOccurs='0' > <xs:element name="output" type="wsdl:tParam" /> <xs:element name="fault" type="wsdl:tFault" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:sequence> </xs:group> <xs:group name="solicit-response-or-notification-operation" > <xs:sequence> <xs:element name="output" type="wsdl:tParam" /> <xs:sequence minOccurs='0' > <xs:element name="input" type="wsdl:tParam" /> <xs:element name="fault" type="wsdl:tFault" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:sequence> </xs:group> <xs:complexType name="tParam" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleAttributesDocumented" > <xs:attribute name="name" type="xs:NCName" use="optional" /> <xs:attribute name="message" type="xs:QName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tFault" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleAttributesDocumented" > <xs:attribute name="name" type="xs:NCName" use="required" /> <xs:attribute name="message" type="xs:QName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tBinding" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:element name="operation" type="wsdl:tBindingOperation" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> <xs:attribute name="type" type="xs:QName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tBindingOperationMessage" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:attribute name="name" type="xs:NCName" use="optional" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tBindingOperationFault" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tBindingOperation" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:element name="input" type="wsdl:tBindingOperationMessage" minOccurs="0" /> <xs:element name="output" type="wsdl:tBindingOperationMessage" minOccurs="0" /> <xs:element name="fault" type="wsdl:tBindingOperationFault" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tService" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:sequence> <xs:element name="port" type="wsdl:tPort" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="tPort" > <xs:complexContent> <xs:extension base="wsdl:tExtensibleDocumented" > <xs:attribute name="name" type="xs:NCName" use="required" /> <xs:attribute name="binding" type="xs:QName" use="required" /> </xs:extension> </xs:complexContent> </xs:complexType> <xs:attribute name="arrayType" type="xs:string" /> <xs:attribute name="required" type="xs:boolean" /> <xs:complexType name="tExtensibilityElement" abstract="true" > <xs:attribute ref="wsdl:required" use="optional" /> </xs:complexType> </xs:schema>����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XHTML/�����������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020051�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XHTML/xhtml1-strict.xsd������������������������������������������0000664�0000000�0000000�00000177705�14211403446�0023335�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema version="1.0" xml:lang="en" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" elementFormDefault="qualified"> <xs:annotation> <xs:documentation> XHTML 1.0 (Second Edition) Strict in XML Schema This is the same as HTML 4 Strict except for changes due to the differences between XML and SGML. Namespace = http://www.w3.org/1999/xhtml For further information, see: http://www.w3.org/TR/xhtml1 Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio), All Rights Reserved. The DTD version is identified by the PUBLIC and SYSTEM identifiers: PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" $Id: xhtml1-strict.xsd,v 1.2 2002/08/28 08:05:44 mimasa Exp $ </xs:documentation> </xs:annotation> <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> <xs:annotation> <xs:documentation> ================ Character mnemonic entities ========================= XHTML entity sets are identified by the PUBLIC and SYSTEM identifiers: PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN" SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent" PUBLIC "-//W3C//ENTITIES Special for XHTML//EN" SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent" PUBLIC "-//W3C//ENTITIES Symbols for XHTML//EN" SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent" </xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> ================== Imported Names ==================================== </xs:documentation> </xs:annotation> <xs:simpleType name="ContentType"> <xs:annotation> <xs:documentation> media type, as per [RFC2045] </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="ContentTypes"> <xs:annotation> <xs:documentation> comma-separated list of media types, as per [RFC2045] </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Charset"> <xs:annotation> <xs:documentation> a character encoding, as per [RFC2045] </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Charsets"> <xs:annotation> <xs:documentation> a space separated list of character encodings, as per [RFC2045] </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="LanguageCode"> <xs:annotation> <xs:documentation> a language code, as per [RFC3066] </xs:documentation> </xs:annotation> <xs:restriction base="xs:language"/> </xs:simpleType> <xs:simpleType name="Character"> <xs:annotation> <xs:documentation> a single character, as per section 2.2 of [XML] </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> <xs:length value="1" fixed="true"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Number"> <xs:annotation> <xs:documentation> one or more digits </xs:documentation> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"> <xs:pattern value="[0-9]+"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="tabindexNumber"> <xs:annotation> <xs:documentation> tabindex attribute specifies the position of the current element in the tabbing order for the current document. This value must be a number between 0 and 32767. User agents should ignore leading zeros. </xs:documentation> </xs:annotation> <xs:restriction base="Number"> <xs:minInclusive value="0"/> <xs:maxInclusive value="32767"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="LinkTypes"> <xs:annotation> <xs:documentation> space-separated list of link types </xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKENS"/> </xs:simpleType> <xs:simpleType name="MediaDesc"> <xs:annotation> <xs:documentation> single or comma-separated list of media descriptors </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> <xs:pattern value="[^,]+(,\s*[^,]+)*"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="URI"> <xs:annotation> <xs:documentation> a Uniform Resource Identifier, see [RFC2396] </xs:documentation> </xs:annotation> <xs:restriction base="xs:anyURI"/> </xs:simpleType> <xs:simpleType name="UriList"> <xs:annotation> <xs:documentation> a space separated list of Uniform Resource Identifiers </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Datetime"> <xs:annotation> <xs:documentation> date and time information. ISO date format </xs:documentation> </xs:annotation> <xs:restriction base="xs:dateTime"/> </xs:simpleType> <xs:simpleType name="Script"> <xs:annotation> <xs:documentation> script expression </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="StyleSheet"> <xs:annotation> <xs:documentation> style sheet data </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Text"> <xs:annotation> <xs:documentation> used for titles etc. </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:simpleType name="Length"> <xs:annotation> <xs:documentation> nn for pixels or nn% for percentage length </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> <xs:pattern value="[-+]?(\d+|\d+(\.\d+)?%)"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="MultiLength"> <xs:annotation> <xs:documentation> pixel, percentage, or relative </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> <xs:pattern value="[-+]?(\d+|\d+(\.\d+)?%)|[1-9]?(\d+)?\*"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Pixels"> <xs:annotation> <xs:documentation> integer representing length in pixels </xs:documentation> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"/> </xs:simpleType> <xs:annotation> <xs:documentation> these are used for image maps </xs:documentation> </xs:annotation> <xs:simpleType name="Shape"> <xs:restriction base="xs:token"> <xs:enumeration value="rect"/> <xs:enumeration value="circle"/> <xs:enumeration value="poly"/> <xs:enumeration value="default"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Coords"> <xs:annotation> <xs:documentation> comma separated list of lengths </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> <xs:pattern value="[-+]?(\d+|\d+(\.\d+)?%)(,\s*[-+]?(\d+|\d+(\.\d+)?%))*"/> </xs:restriction> </xs:simpleType> <xs:annotation> <xs:documentation> =================== Generic Attributes =============================== </xs:documentation> </xs:annotation> <xs:attributeGroup name="coreattrs"> <xs:annotation> <xs:documentation> core attributes common to most elements id document-wide unique id class space separated list of classes style associated style info title advisory title/amplification </xs:documentation> </xs:annotation> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="class" type="xs:NMTOKENS"/> <xs:attribute name="style" type="StyleSheet"/> <xs:attribute name="title" type="Text"/> </xs:attributeGroup> <xs:attributeGroup name="i18n"> <xs:annotation> <xs:documentation> internationalization attributes lang language code (backwards compatible) xml:lang language code (as per XML 1.0 spec) dir direction for weak/neutral text </xs:documentation> </xs:annotation> <xs:attribute name="lang" type="LanguageCode"/> <xs:attribute ref="xml:lang"/> <xs:attribute name="dir"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="ltr"/> <xs:enumeration value="rtl"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:attributeGroup> <xs:attributeGroup name="events"> <xs:annotation> <xs:documentation> attributes for common UI events onclick a pointer button was clicked ondblclick a pointer button was double clicked onmousedown a pointer button was pressed down onmouseup a pointer button was released onmousemove a pointer was moved onto the element onmouseout a pointer was moved away from the element onkeypress a key was pressed and released onkeydown a key was pressed down onkeyup a key was released </xs:documentation> </xs:annotation> <xs:attribute name="onclick" type="Script"/> <xs:attribute name="ondblclick" type="Script"/> <xs:attribute name="onmousedown" type="Script"/> <xs:attribute name="onmouseup" type="Script"/> <xs:attribute name="onmouseover" type="Script"/> <xs:attribute name="onmousemove" type="Script"/> <xs:attribute name="onmouseout" type="Script"/> <xs:attribute name="onkeypress" type="Script"/> <xs:attribute name="onkeydown" type="Script"/> <xs:attribute name="onkeyup" type="Script"/> </xs:attributeGroup> <xs:attributeGroup name="focus"> <xs:annotation> <xs:documentation> attributes for elements that can get the focus accesskey accessibility key character tabindex position in tabbing order onfocus the element got the focus onblur the element lost the focus </xs:documentation> </xs:annotation> <xs:attribute name="accesskey" type="Character"/> <xs:attribute name="tabindex" type="tabindexNumber"/> <xs:attribute name="onfocus" type="Script"/> <xs:attribute name="onblur" type="Script"/> </xs:attributeGroup> <xs:attributeGroup name="attrs"> <xs:attributeGroup ref="coreattrs"/> <xs:attributeGroup ref="i18n"/> <xs:attributeGroup ref="events"/> </xs:attributeGroup> <xs:annotation> <xs:documentation> =================== Text Elements ==================================== </xs:documentation> </xs:annotation> <xs:group name="special.pre"> <xs:choice> <xs:element ref="br"/> <xs:element ref="span"/> <xs:element ref="bdo"/> <xs:element ref="map"/> </xs:choice> </xs:group> <xs:group name="special"> <xs:choice> <xs:group ref="special.pre"/> <xs:element ref="object"/> <xs:element ref="img"/> </xs:choice> </xs:group> <xs:group name="fontstyle"> <xs:choice> <xs:element ref="tt"/> <xs:element ref="i"/> <xs:element ref="b"/> <xs:element ref="big"/> <xs:element ref="small"/> </xs:choice> </xs:group> <xs:group name="phrase"> <xs:choice> <xs:element ref="em"/> <xs:element ref="strong"/> <xs:element ref="dfn"/> <xs:element ref="code"/> <xs:element ref="q"/> <xs:element ref="samp"/> <xs:element ref="kbd"/> <xs:element ref="var"/> <xs:element ref="cite"/> <xs:element ref="abbr"/> <xs:element ref="acronym"/> <xs:element ref="sub"/> <xs:element ref="sup"/> </xs:choice> </xs:group> <xs:group name="inline.forms"> <xs:choice> <xs:element ref="input"/> <xs:element ref="select"/> <xs:element ref="textarea"/> <xs:element ref="label"/> <xs:element ref="button"/> </xs:choice> </xs:group> <xs:group name="misc.inline"> <xs:choice> <xs:element ref="ins"/> <xs:element ref="del"/> <xs:element ref="script"/> </xs:choice> </xs:group> <xs:group name="misc"> <xs:annotation> <xs:documentation> these can only occur at block level </xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="noscript"/> <xs:group ref="misc.inline"/> </xs:choice> </xs:group> <xs:group name="inline"> <xs:choice> <xs:element ref="a"/> <xs:group ref="special"/> <xs:group ref="fontstyle"/> <xs:group ref="phrase"/> <xs:group ref="inline.forms"/> </xs:choice> </xs:group> <xs:complexType name="Inline" mixed="true"> <xs:annotation> <xs:documentation> "Inline" covers inline or "text-level" elements </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="inline"/> <xs:group ref="misc.inline"/> </xs:choice> </xs:complexType> <xs:annotation> <xs:documentation> ================== Block level elements ============================== </xs:documentation> </xs:annotation> <xs:group name="heading"> <xs:choice> <xs:element ref="h1"/> <xs:element ref="h2"/> <xs:element ref="h3"/> <xs:element ref="h4"/> <xs:element ref="h5"/> <xs:element ref="h6"/> </xs:choice> </xs:group> <xs:group name="lists"> <xs:choice> <xs:element ref="ul"/> <xs:element ref="ol"/> <xs:element ref="dl"/> </xs:choice> </xs:group> <xs:group name="blocktext"> <xs:choice> <xs:element ref="pre"/> <xs:element ref="hr"/> <xs:element ref="blockquote"/> <xs:element ref="address"/> </xs:choice> </xs:group> <xs:group name="block"> <xs:choice> <xs:element ref="p"/> <xs:group ref="heading"/> <xs:element ref="div"/> <xs:group ref="lists"/> <xs:group ref="blocktext"/> <xs:element ref="fieldset"/> <xs:element ref="table"/> </xs:choice> </xs:group> <xs:complexType name="Block"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="block"/> <xs:element ref="form"/> <xs:group ref="misc"/> </xs:choice> </xs:complexType> <xs:complexType name="Flow" mixed="true"> <xs:annotation> <xs:documentation> "Flow" mixes block and inline and is used for list items etc. </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="block"/> <xs:element ref="form"/> <xs:group ref="inline"/> <xs:group ref="misc"/> </xs:choice> </xs:complexType> <xs:annotation> <xs:documentation> ================== Content models for exclusions ===================== </xs:documentation> </xs:annotation> <xs:complexType name="a.content" mixed="true"> <xs:annotation> <xs:documentation> a elements use "Inline" excluding a </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="special"/> <xs:group ref="fontstyle"/> <xs:group ref="phrase"/> <xs:group ref="inline.forms"/> <xs:group ref="misc.inline"/> </xs:choice> </xs:complexType> <xs:complexType name="pre.content" mixed="true"> <xs:annotation> <xs:documentation> pre uses "Inline" excluding big, small, sup or sup </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="a"/> <xs:group ref="fontstyle"/> <xs:group ref="phrase"/> <xs:group ref="special.pre"/> <xs:group ref="misc.inline"/> <xs:group ref="inline.forms"/> </xs:choice> </xs:complexType> <xs:complexType name="form.content"> <xs:annotation> <xs:documentation> form uses "Block" excluding form </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="block"/> <xs:group ref="misc"/> </xs:choice> </xs:complexType> <xs:complexType name="button.content" mixed="true"> <xs:annotation> <xs:documentation> button uses "Flow" but excludes a, form and form controls </xs:documentation> </xs:annotation> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="p"/> <xs:group ref="heading"/> <xs:element ref="div"/> <xs:group ref="lists"/> <xs:group ref="blocktext"/> <xs:element ref="table"/> <xs:group ref="special"/> <xs:group ref="fontstyle"/> <xs:group ref="phrase"/> <xs:group ref="misc"/> </xs:choice> </xs:complexType> <xs:annotation> <xs:documentation> ================ Document Structure ================================== </xs:documentation> </xs:annotation> <xs:element name="html"> <xs:complexType> <xs:sequence> <xs:element ref="head"/> <xs:element ref="body"/> </xs:sequence> <xs:attributeGroup ref="i18n"/> <xs:attribute name="id" type="xs:ID"/> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ================ Document Head ======================================= </xs:documentation> </xs:annotation> <xs:group name="head.misc"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="script"/> <xs:element ref="style"/> <xs:element ref="meta"/> <xs:element ref="link"/> <xs:element ref="object"/> </xs:choice> </xs:sequence> </xs:group> <xs:element name="head"> <xs:annotation> <xs:documentation> content model is "head.misc" combined with a single title and an optional base element in any order </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:group ref="head.misc"/> <xs:choice> <xs:sequence> <xs:element ref="title"/> <xs:group ref="head.misc"/> <xs:sequence minOccurs="0"> <xs:element ref="base"/> <xs:group ref="head.misc"/> </xs:sequence> </xs:sequence> <xs:sequence> <xs:element ref="base"/> <xs:group ref="head.misc"/> <xs:element ref="title"/> <xs:group ref="head.misc"/> </xs:sequence> </xs:choice> </xs:sequence> <xs:attributeGroup ref="i18n"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="profile" type="URI"/> </xs:complexType> </xs:element> <xs:element name="title"> <xs:annotation> <xs:documentation> The title element is not considered part of the flow of text. It should be displayed, for example as the page header or window title. Exactly one title is required per document. </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:attributeGroup ref="i18n"/> <xs:attribute name="id" type="xs:ID"/> </xs:complexType> </xs:element> <xs:element name="base"> <xs:annotation> <xs:documentation> document base URI </xs:documentation> </xs:annotation> <xs:complexType> <xs:attribute name="href" use="required" type="URI"/> <xs:attribute name="id" type="xs:ID"/> </xs:complexType> </xs:element> <xs:element name="meta"> <xs:annotation> <xs:documentation> generic metainformation </xs:documentation> </xs:annotation> <xs:complexType> <xs:attributeGroup ref="i18n"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="http-equiv"/> <xs:attribute name="name"/> <xs:attribute name="content" use="required"/> <xs:attribute name="scheme"/> </xs:complexType> </xs:element> <xs:element name="link"> <xs:annotation> <xs:documentation> Relationship values can be used in principle: a) for document specific toolbars/menus when used with the link element in document head e.g. start, contents, previous, next, index, end, help b) to link to a separate style sheet (rel="stylesheet") c) to make a link to a script (rel="script") d) by stylesheets to control how collections of html nodes are rendered into printed documents e) to make a link to a printable version of this document e.g. a PostScript or PDF version (rel="alternate" media="print") </xs:documentation> </xs:annotation> <xs:complexType> <xs:attributeGroup ref="attrs"/> <xs:attribute name="charset" type="Charset"/> <xs:attribute name="href" type="URI"/> <xs:attribute name="hreflang" type="LanguageCode"/> <xs:attribute name="type" type="ContentType"/> <xs:attribute name="rel" type="LinkTypes"/> <xs:attribute name="rev" type="LinkTypes"/> <xs:attribute name="media" type="MediaDesc"/> </xs:complexType> </xs:element> <xs:element name="style"> <xs:annotation> <xs:documentation> style info, which may include CDATA sections </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:attributeGroup ref="i18n"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="type" use="required" type="ContentType"/> <xs:attribute name="media" type="MediaDesc"/> <xs:attribute name="title" type="Text"/> <xs:attribute ref="xml:space" fixed="preserve"/> </xs:complexType> </xs:element> <xs:element name="script"> <xs:annotation> <xs:documentation> script statements, which may include CDATA sections </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="charset" type="Charset"/> <xs:attribute name="type" use="required" type="ContentType"/> <xs:attribute name="src" type="URI"/> <xs:attribute name="defer"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="defer"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute ref="xml:space" fixed="preserve"/> </xs:complexType> </xs:element> <xs:element name="noscript"> <xs:annotation> <xs:documentation> alternate content container for non script-based rendering </xs:documentation> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="Block"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Document Body ==================================== </xs:documentation> </xs:annotation> <xs:element name="body"> <xs:complexType> <xs:complexContent> <xs:extension base="Block"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="onload" type="Script"/> <xs:attribute name="onunload" type="Script"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="div"> <xs:annotation> <xs:documentation> generic language/style container </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Paragraphs ======================================= </xs:documentation> </xs:annotation> <xs:element name="p"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Headings ========================================= There are six levels of headings from h1 (the most important) to h6 (the least important). </xs:documentation> </xs:annotation> <xs:element name="h1"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="h2"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="h3"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="h4"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="h5"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="h6"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Lists ============================================ </xs:documentation> </xs:annotation> <xs:element name="ul"> <xs:annotation> <xs:documentation> Unordered list </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="li"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> </xs:complexType> </xs:element> <xs:element name="ol"> <xs:annotation> <xs:documentation> Ordered (numbered) list </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="li"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> </xs:complexType> </xs:element> <xs:element name="li"> <xs:annotation> <xs:documentation> list item </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> definition lists - dt for term, dd for its definition </xs:documentation> </xs:annotation> <xs:element name="dl"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element ref="dt"/> <xs:element ref="dd"/> </xs:choice> <xs:attributeGroup ref="attrs"/> </xs:complexType> </xs:element> <xs:element name="dt"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="dd"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Address ========================================== </xs:documentation> </xs:annotation> <xs:element name="address"> <xs:annotation> <xs:documentation> information on author </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Horizontal Rule ================================== </xs:documentation> </xs:annotation> <xs:element name="hr"> <xs:complexType> <xs:attributeGroup ref="attrs"/> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Preformatted Text ================================ </xs:documentation> </xs:annotation> <xs:element name="pre"> <xs:annotation> <xs:documentation> content is "Inline" excluding "img|object|big|small|sub|sup" </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="pre.content"> <xs:attributeGroup ref="attrs"/> <xs:attribute ref="xml:space" fixed="preserve"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Block-like Quotes ================================ </xs:documentation> </xs:annotation> <xs:element name="blockquote"> <xs:complexType> <xs:complexContent> <xs:extension base="Block"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="cite" type="URI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Inserted/Deleted Text ============================ ins/del are allowed in block and inline content, but its inappropriate to include block content within an ins element occurring in inline content. </xs:documentation> </xs:annotation> <xs:element name="ins"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="cite" type="URI"/> <xs:attribute name="datetime" type="Datetime"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="del"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="cite" type="URI"/> <xs:attribute name="datetime" type="Datetime"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ================== The Anchor Element ================================ </xs:documentation> </xs:annotation> <xs:element name="a"> <xs:annotation> <xs:documentation> content is "Inline" except that anchors shouldn't be nested </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="a.content"> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="focus"/> <xs:attribute name="charset" type="Charset"/> <xs:attribute name="type" type="ContentType"/> <xs:attribute name="name" type="xs:NMTOKEN"/> <xs:attribute name="href" type="URI"/> <xs:attribute name="hreflang" type="LanguageCode"/> <xs:attribute name="rel" type="LinkTypes"/> <xs:attribute name="rev" type="LinkTypes"/> <xs:attribute name="shape" default="rect" type="Shape"/> <xs:attribute name="coords" type="Coords"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ===================== Inline Elements ================================ </xs:documentation> </xs:annotation> <xs:element name="span"> <xs:annotation> <xs:documentation> generic language/style container </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="bdo"> <xs:annotation> <xs:documentation> I18N BiDi over-ride </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="coreattrs"/> <xs:attributeGroup ref="events"/> <xs:attribute name="lang" type="LanguageCode"/> <xs:attribute ref="xml:lang"/> <xs:attribute name="dir" use="required"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="ltr"/> <xs:enumeration value="rtl"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="br"> <xs:annotation> <xs:documentation> forced line break </xs:documentation> </xs:annotation> <xs:complexType> <xs:attributeGroup ref="coreattrs"/> </xs:complexType> </xs:element> <xs:element name="em"> <xs:annotation> <xs:documentation> emphasis </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="strong"> <xs:annotation> <xs:documentation> strong emphasis </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="dfn"> <xs:annotation> <xs:documentation> definitional </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="code"> <xs:annotation> <xs:documentation> program code </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="samp"> <xs:annotation> <xs:documentation> sample </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="kbd"> <xs:annotation> <xs:documentation> something user would type </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="var"> <xs:annotation> <xs:documentation> variable </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="cite"> <xs:annotation> <xs:documentation> citation </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="abbr"> <xs:annotation> <xs:documentation> abbreviation </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="acronym"> <xs:annotation> <xs:documentation> acronym </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="q"> <xs:annotation> <xs:documentation> inlined quote </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="cite" type="URI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="sub"> <xs:annotation> <xs:documentation> subscript </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="sup"> <xs:annotation> <xs:documentation> superscript </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="tt"> <xs:annotation> <xs:documentation> fixed pitch font </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="i"> <xs:annotation> <xs:documentation> italic font </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="b"> <xs:annotation> <xs:documentation> bold font </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="big"> <xs:annotation> <xs:documentation> bigger font </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="small"> <xs:annotation> <xs:documentation> smaller font </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ==================== Object ====================================== object is used to embed objects as part of HTML pages. param elements should precede other content. Parameters can also be expressed as attribute/value pairs on the object element itself when brevity is desired. </xs:documentation> </xs:annotation> <xs:element name="object"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="param"/> <xs:group ref="block"/> <xs:element ref="form"/> <xs:group ref="inline"/> <xs:group ref="misc"/> </xs:choice> <xs:attributeGroup ref="attrs"/> <xs:attribute name="declare"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="declare"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="classid" type="URI"/> <xs:attribute name="codebase" type="URI"/> <xs:attribute name="data" type="URI"/> <xs:attribute name="type" type="ContentType"/> <xs:attribute name="codetype" type="ContentType"/> <xs:attribute name="archive" type="UriList"/> <xs:attribute name="standby" type="Text"/> <xs:attribute name="height" type="Length"/> <xs:attribute name="width" type="Length"/> <xs:attribute name="usemap" type="URI"/> <xs:attribute name="name" type="xs:NMTOKEN"/> <xs:attribute name="tabindex" type="tabindexNumber"/> </xs:complexType> </xs:element> <xs:element name="param"> <xs:annotation> <xs:documentation> param is used to supply a named property value. In XML it would seem natural to follow RDF and support an abbreviated syntax where the param elements are replaced by attribute value pairs on the object start tag. </xs:documentation> </xs:annotation> <xs:complexType> <xs:attribute name="id" type="xs:ID"/> <xs:attribute name="name"/> <xs:attribute name="value"/> <xs:attribute name="valuetype" default="data"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="data"/> <xs:enumeration value="ref"/> <xs:enumeration value="object"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="type" type="ContentType"/> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> =================== Images =========================================== To avoid accessibility problems for people who aren't able to see the image, you should provide a text description using the alt and longdesc attributes. In addition, avoid the use of server-side image maps. Note that in this DTD there is no name attribute. That is only available in the transitional and frameset DTD. </xs:documentation> </xs:annotation> <xs:element name="img"> <xs:complexType> <xs:attributeGroup ref="attrs"/> <xs:attribute name="src" use="required" type="URI"/> <xs:attribute name="alt" use="required" type="Text"/> <xs:attribute name="longdesc" type="URI"/> <xs:attribute name="height" type="Length"/> <xs:attribute name="width" type="Length"/> <xs:attribute name="usemap" type="URI"> <xs:annotation> <xs:documentation> usemap points to a map element which may be in this document or an external document, although the latter is not widely supported </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="ismap"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="ismap"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ================== Client-side image maps ============================ These can be placed in the same document or grouped in a separate document although this isn't yet widely supported </xs:documentation> </xs:annotation> <xs:element name="map"> <xs:complexType> <xs:choice> <xs:choice maxOccurs="unbounded"> <xs:group ref="block"/> <xs:element ref="form"/> <xs:group ref="misc"/> </xs:choice> <xs:element maxOccurs="unbounded" ref="area"/> </xs:choice> <xs:attributeGroup ref="i18n"/> <xs:attributeGroup ref="events"/> <xs:attribute name="id" use="required" type="xs:ID"/> <xs:attribute name="class"/> <xs:attribute name="style" type="StyleSheet"/> <xs:attribute name="title" type="Text"/> <xs:attribute name="name" type="xs:NMTOKEN"/> </xs:complexType> </xs:element> <xs:element name="area"> <xs:complexType> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="focus"/> <xs:attribute name="shape" default="rect" type="Shape"/> <xs:attribute name="coords" type="Coords"/> <xs:attribute name="href" type="URI"/> <xs:attribute name="nohref"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="nohref"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="alt" use="required" type="Text"/> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ================ Forms =============================================== </xs:documentation> </xs:annotation> <xs:element name="form"> <xs:complexType> <xs:complexContent> <xs:extension base="form.content"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="action" use="required" type="URI"/> <xs:attribute name="method" default="get"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="get"/> <xs:enumeration value="post"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="enctype" type="ContentType" default="application/x-www-form-urlencoded"/> <xs:attribute name="onsubmit" type="Script"/> <xs:attribute name="onreset" type="Script"/> <xs:attribute name="accept" type="ContentTypes"/> <xs:attribute name="accept-charset" type="Charsets"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="label"> <xs:annotation> <xs:documentation> Each label must not contain more than ONE field Label elements shouldn't be nested. </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="for" type="xs:IDREF"/> <xs:attribute name="accesskey" type="Character"/> <xs:attribute name="onfocus" type="Script"/> <xs:attribute name="onblur" type="Script"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:simpleType name="InputType"> <xs:restriction base="xs:token"> <xs:enumeration value="text"/> <xs:enumeration value="password"/> <xs:enumeration value="checkbox"/> <xs:enumeration value="radio"/> <xs:enumeration value="submit"/> <xs:enumeration value="reset"/> <xs:enumeration value="file"/> <xs:enumeration value="hidden"/> <xs:enumeration value="image"/> <xs:enumeration value="button"/> </xs:restriction> </xs:simpleType> <xs:element name="input"> <xs:annotation> <xs:documentation> form control </xs:documentation> </xs:annotation> <xs:complexType> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="focus"/> <xs:attribute name="type" default="text" type="InputType"/> <xs:attribute name="name"> <xs:annotation> <xs:documentation> the name attribute is required for all but submit & reset </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="value"/> <xs:attribute name="checked"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="checked"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="readonly"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="readonly"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="size"/> <xs:attribute name="maxlength" type="Number"/> <xs:attribute name="src" type="URI"/> <xs:attribute name="alt"/> <xs:attribute name="usemap" type="URI"/> <xs:attribute name="onselect" type="Script"/> <xs:attribute name="onchange" type="Script"/> <xs:attribute name="accept" type="ContentTypes"/> </xs:complexType> </xs:element> <xs:element name="select"> <xs:annotation> <xs:documentation> option selector </xs:documentation> </xs:annotation> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element ref="optgroup"/> <xs:element ref="option"/> </xs:choice> <xs:attributeGroup ref="attrs"/> <xs:attribute name="name"/> <xs:attribute name="size" type="Number"/> <xs:attribute name="multiple"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="multiple"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="tabindex" type="tabindexNumber"/> <xs:attribute name="onfocus" type="Script"/> <xs:attribute name="onblur" type="Script"/> <xs:attribute name="onchange" type="Script"/> </xs:complexType> </xs:element> <xs:element name="optgroup"> <xs:annotation> <xs:documentation> option group </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="option"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="label" use="required" type="Text"/> </xs:complexType> </xs:element> <xs:element name="option"> <xs:annotation> <xs:documentation> selectable choice </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="selected"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="selected"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="label" type="Text"/> <xs:attribute name="value"/> </xs:complexType> </xs:element> <xs:element name="textarea"> <xs:annotation> <xs:documentation> multi-line text field </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="focus"/> <xs:attribute name="name"/> <xs:attribute name="rows" use="required" type="Number"/> <xs:attribute name="cols" use="required" type="Number"/> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="readonly"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="readonly"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="onselect" type="Script"/> <xs:attribute name="onchange" type="Script"/> </xs:complexType> </xs:element> <xs:element name="fieldset"> <xs:annotation> <xs:documentation> The fieldset element is used to group form fields. Only one legend element should occur in the content and if present should only be preceded by whitespace. NOTE: this content model is different from the XHTML 1.0 DTD, closer to the intended content model in HTML4 DTD </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:sequence> <xs:element ref="legend"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:group ref="block"/> <xs:element ref="form"/> <xs:group ref="inline"/> <xs:group ref="misc"/> </xs:choice> </xs:sequence> <xs:attributeGroup ref="attrs"/> </xs:complexType> </xs:element> <xs:element name="legend"> <xs:annotation> <xs:documentation> fieldset label </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="accesskey" type="Character"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="button"> <xs:annotation> <xs:documentation> Content is "Flow" excluding a, form and form controls </xs:documentation> </xs:annotation> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="button.content"> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="focus"/> <xs:attribute name="name"/> <xs:attribute name="value"/> <xs:attribute name="type" default="submit"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="button"/> <xs:enumeration value="submit"/> <xs:enumeration value="reset"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="disabled"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="disabled"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> ======================= Tables ======================================= Derived from IETF HTML table standard, see [RFC1942] </xs:documentation> </xs:annotation> <xs:simpleType name="TFrame"> <xs:annotation> <xs:documentation> The border attribute sets the thickness of the frame around the table. The default units are screen pixels. The frame attribute specifies which parts of the frame around the table should be rendered. The values are not the same as CALS to avoid a name clash with the valign attribute. </xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:enumeration value="void"/> <xs:enumeration value="above"/> <xs:enumeration value="below"/> <xs:enumeration value="hsides"/> <xs:enumeration value="lhs"/> <xs:enumeration value="rhs"/> <xs:enumeration value="vsides"/> <xs:enumeration value="box"/> <xs:enumeration value="border"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="TRules"> <xs:annotation> <xs:documentation> The rules attribute defines which rules to draw between cells: If rules is absent then assume: "none" if border is absent or border="0" otherwise "all" </xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:enumeration value="none"/> <xs:enumeration value="groups"/> <xs:enumeration value="rows"/> <xs:enumeration value="cols"/> <xs:enumeration value="all"/> </xs:restriction> </xs:simpleType> <xs:attributeGroup name="cellhalign"> <xs:annotation> <xs:documentation> horizontal alignment attributes for cell contents char alignment char, e.g. char=':' charoff offset for alignment char </xs:documentation> </xs:annotation> <xs:attribute name="align"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="left"/> <xs:enumeration value="center"/> <xs:enumeration value="right"/> <xs:enumeration value="justify"/> <xs:enumeration value="char"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="char" type="Character"/> <xs:attribute name="charoff" type="Length"/> </xs:attributeGroup> <xs:attributeGroup name="cellvalign"> <xs:annotation> <xs:documentation> vertical alignment attributes for cell contents </xs:documentation> </xs:annotation> <xs:attribute name="valign"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="top"/> <xs:enumeration value="middle"/> <xs:enumeration value="bottom"/> <xs:enumeration value="baseline"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:attributeGroup> <xs:element name="table"> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" ref="caption"/> <xs:choice> <xs:element minOccurs="0" maxOccurs="unbounded" ref="col"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="colgroup"/> </xs:choice> <xs:element minOccurs="0" ref="thead"/> <xs:element minOccurs="0" ref="tfoot"/> <xs:choice> <xs:element maxOccurs="unbounded" ref="tbody"/> <xs:element maxOccurs="unbounded" ref="tr"/> </xs:choice> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attribute name="summary" type="Text"/> <xs:attribute name="width" type="Length"/> <xs:attribute name="border" type="Pixels"/> <xs:attribute name="frame" type="TFrame"/> <xs:attribute name="rules" type="TRules"/> <xs:attribute name="cellspacing" type="Length"/> <xs:attribute name="cellpadding" type="Length"/> </xs:complexType> </xs:element> <xs:element name="caption"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Inline"> <xs:attributeGroup ref="attrs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> Use thead to duplicate headers when breaking table across page boundaries, or for static headers when tbody sections are rendered in scrolling panel. Use tfoot to duplicate footers when breaking table across page boundaries, or for static footers when tbody sections are rendered in scrolling panel. Use multiple tbody sections when rules are needed between groups of table rows. </xs:documentation> </xs:annotation> <xs:element name="thead"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="tr"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:element name="tfoot"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="tr"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:element name="tbody"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="tr"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:element name="colgroup"> <xs:annotation> <xs:documentation> colgroup groups a set of col elements. It allows you to group several semantically related columns together. </xs:documentation> </xs:annotation> <xs:complexType> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="col"/> </xs:sequence> <xs:attributeGroup ref="attrs"/> <xs:attribute name="span" default="1" type="Number"/> <xs:attribute name="width" type="MultiLength"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:element name="col"> <xs:annotation> <xs:documentation> col elements define the alignment properties for cells in one or more columns. The width attribute specifies the width of the columns, e.g. width=64 width in screen pixels width=0.5* relative width of 0.5 The span attribute causes the attributes of one col element to apply to more than one column. </xs:documentation> </xs:annotation> <xs:complexType> <xs:attributeGroup ref="attrs"/> <xs:attribute name="span" default="1" type="Number"/> <xs:attribute name="width" type="MultiLength"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:element name="tr"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element ref="th"/> <xs:element ref="td"/> </xs:choice> <xs:attributeGroup ref="attrs"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:complexType> </xs:element> <xs:simpleType name="Scope"> <xs:annotation> <xs:documentation> Scope is simpler than headers attribute for common tables </xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:enumeration value="row"/> <xs:enumeration value="col"/> <xs:enumeration value="rowgroup"/> <xs:enumeration value="colgroup"/> </xs:restriction> </xs:simpleType> <xs:annotation> <xs:documentation> th is for headers, td for data and for cells acting as both </xs:documentation> </xs:annotation> <xs:element name="th"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="abbr" type="Text"/> <xs:attribute name="axis"/> <xs:attribute name="headers" type="xs:IDREFS"/> <xs:attribute name="scope" type="Scope"/> <xs:attribute name="rowspan" default="1" type="Number"/> <xs:attribute name="colspan" default="1" type="Number"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="td"> <xs:complexType mixed="true"> <xs:complexContent> <xs:extension base="Flow"> <xs:attributeGroup ref="attrs"/> <xs:attribute name="abbr" type="Text"/> <xs:attribute name="axis"/> <xs:attribute name="headers" type="xs:IDREFS"/> <xs:attribute name="scope" type="Scope"/> <xs:attribute name="rowspan" default="1" type="Number"/> <xs:attribute name="colspan" default="1" type="Number"/> <xs:attributeGroup ref="cellhalign"/> <xs:attributeGroup ref="cellvalign"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:schema> �����������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XLINK/�����������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020042�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XLINK/xlink.xsd��������������������������������������������������0000664�0000000�0000000�00000017563�14211403446�0021723�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"> <xs:annotation> <xs:documentation>This schema document provides attribute declarations and attribute group, complex type and simple type definitions which can be used in the construction of user schemas to define the structure of particular linking constructs, e.g. <![CDATA[ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xl="http://www.w3.org/1999/xlink"> <xs:import namespace="http://www.w3.org/1999/xlink" location="http://www.w3.org/1999/xlink.xsd"> <xs:element name="mySimple"> <xs:complexType> ... <xs:attributeGroup ref="xl:simpleAttrs"/> ... </xs:complexType> </xs:element> ... </xs:schema>]]></xs:documentation> </xs:annotation> <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/> <xs:attribute name="type" type="xlink:typeType"/> <xs:simpleType name="typeType"> <xs:restriction base="xs:token"> <xs:enumeration value="simple"/> <xs:enumeration value="extended"/> <xs:enumeration value="title"/> <xs:enumeration value="resource"/> <xs:enumeration value="locator"/> <xs:enumeration value="arc"/> </xs:restriction> </xs:simpleType> <xs:attribute name="href" type="xlink:hrefType"/> <xs:simpleType name="hrefType"> <xs:restriction base="xs:anyURI"/> </xs:simpleType> <xs:attribute name="role" type="xlink:roleType"/> <xs:simpleType name="roleType"> <xs:restriction base="xs:anyURI"> <xs:minLength value="1"/> </xs:restriction> </xs:simpleType> <xs:attribute name="arcrole" type="xlink:arcroleType"/> <xs:simpleType name="arcroleType"> <xs:restriction base="xs:anyURI"> <xs:minLength value="1"/> </xs:restriction> </xs:simpleType> <xs:attribute name="title" type="xlink:titleAttrType"/> <xs:simpleType name="titleAttrType"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:attribute name="show" type="xlink:showType"/> <xs:simpleType name="showType"> <xs:restriction base="xs:token"> <xs:enumeration value="new"/> <xs:enumeration value="replace"/> <xs:enumeration value="embed"/> <xs:enumeration value="other"/> <xs:enumeration value="none"/> </xs:restriction> </xs:simpleType> <xs:attribute name="actuate" type="xlink:actuateType"/> <xs:simpleType name="actuateType"> <xs:restriction base="xs:token"> <xs:enumeration value="onLoad"/> <xs:enumeration value="onRequest"/> <xs:enumeration value="other"/> <xs:enumeration value="none"/> </xs:restriction> </xs:simpleType> <xs:attribute name="label" type="xlink:labelType"/> <xs:simpleType name="labelType"> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:attribute name="from" type="xlink:fromType"/> <xs:simpleType name="fromType"> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:attribute name="to" type="xlink:toType"/> <xs:simpleType name="toType"> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:attributeGroup name="simpleAttrs"> <xs:attribute ref="xlink:type" fixed="simple"/> <xs:attribute ref="xlink:href"/> <xs:attribute ref="xlink:role"/> <xs:attribute ref="xlink:arcrole"/> <xs:attribute ref="xlink:title"/> <xs:attribute ref="xlink:show"/> <xs:attribute ref="xlink:actuate"/> </xs:attributeGroup> <xs:group name="simpleModel"> <xs:sequence> <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType mixed="true" name="simple"> <xs:annotation> <xs:documentation> Intended for use as the type of user-declared elements to make them simple links. </xs:documentation> </xs:annotation> <xs:group ref="xlink:simpleModel"/> <xs:attributeGroup ref="xlink:simpleAttrs"/> </xs:complexType> <xs:attributeGroup name="extendedAttrs"> <xs:attribute ref="xlink:type" fixed="extended" use="required"/> <xs:attribute ref="xlink:role"/> <xs:attribute ref="xlink:title"/> </xs:attributeGroup> <xs:group name="extendedModel"> <xs:choice> <xs:element ref="xlink:title"/> <xs:element ref="xlink:resource"/> <xs:element ref="xlink:locator"/> <xs:element ref="xlink:arc"/> </xs:choice> </xs:group> <xs:complexType name="extended"> <xs:annotation> <xs:documentation> Intended for use as the type of user-declared elements to make them extended links. Note that the elements referenced in the content model are all abstract. The intention is that by simply declaring elements with these as their substitutionGroup, all the right things will happen. </xs:documentation> </xs:annotation> <xs:group ref="xlink:extendedModel" minOccurs="0" maxOccurs="unbounded"/> <xs:attributeGroup ref="xlink:extendedAttrs"/> </xs:complexType> <xs:element name="title" type="xlink:titleEltType" abstract="true"/> <xs:attributeGroup name="titleAttrs"> <xs:attribute ref="xlink:type" fixed="title" use="required"/> <xs:attribute ref="xml:lang"> <xs:annotation> <xs:documentation> xml:lang is not required, but provides much of the motivation for title elements in addition to attributes, and so is provided here for convenience. </xs:documentation> </xs:annotation> </xs:attribute> </xs:attributeGroup> <xs:group name="titleModel"> <xs:sequence> <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType mixed="true" name="titleEltType"> <xs:group ref="xlink:titleModel"/> <xs:attributeGroup ref="xlink:titleAttrs"/> </xs:complexType> <xs:element name="resource" type="xlink:resourceType" abstract="true"/> <xs:attributeGroup name="resourceAttrs"> <xs:attribute ref="xlink:type" fixed="resource" use="required"/> <xs:attribute ref="xlink:role"/> <xs:attribute ref="xlink:title"/> <xs:attribute ref="xlink:label"/> </xs:attributeGroup> <xs:group name="resourceModel"> <xs:sequence> <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType mixed="true" name="resourceType"> <xs:group ref="xlink:resourceModel"/> <xs:attributeGroup ref="xlink:resourceAttrs"/> </xs:complexType> <xs:element name="locator" type="xlink:locatorType" abstract="true"/> <xs:attributeGroup name="locatorAttrs"> <xs:attribute ref="xlink:type" fixed="locator" use="required"/> <xs:attribute ref="xlink:href" use="required"/> <xs:attribute ref="xlink:role"/> <xs:attribute ref="xlink:title"/> <xs:attribute ref="xlink:label"> <xs:annotation> <xs:documentation> label is not required, but locators have no particular XLink function if they are not labeled. </xs:documentation> </xs:annotation> </xs:attribute> </xs:attributeGroup> <xs:group name="locatorModel"> <xs:sequence> <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType name="locatorType"> <xs:group ref="xlink:locatorModel"/> <xs:attributeGroup ref="xlink:locatorAttrs"/> </xs:complexType> <xs:element name="arc" type="xlink:arcType" abstract="true"/> <xs:attributeGroup name="arcAttrs"> <xs:attribute ref="xlink:type" fixed="arc" use="required"/> <xs:attribute ref="xlink:arcrole"/> <xs:attribute ref="xlink:title"/> <xs:attribute ref="xlink:show"/> <xs:attribute ref="xlink:actuate"/> <xs:attribute ref="xlink:from"/> <xs:attribute ref="xlink:to"> <xs:annotation> <xs:documentation> from and to have default behavior when values are missing </xs:documentation> </xs:annotation> </xs:attribute> </xs:attributeGroup> <xs:group name="arcModel"> <xs:sequence> <xs:element ref="xlink:title" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType name="arcType"> <xs:group ref="xlink:arcModel"/> <xs:attributeGroup ref="xlink:arcAttrs"/> </xs:complexType> </xs:schema>���������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XML/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017615�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XML/xml_minimal.xsd����������������������������������������������0000664�0000000�0000000�00000002375�14211403446�0022652�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <?xml-stylesheet href="../../2008/09/xsd.xsl" type="text/xsl"?> <xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en"> <!-- A minimal schema that not requires the loading of xhtml namespace --> <!-- References for XML namespace: * https://www.w3.org/2001/xml.xsd (link updated with latest version) * http://www.w3.org/2009/01/xml.xsd (permanent link for this version) --> <xs:attribute name="lang"> <xs:simpleType> <xs:union memberTypes="xs:language"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value=""/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> </xs:attribute> <xs:attribute name="space"> <xs:simpleType> <xs:restriction base="xs:NCName"> <xs:enumeration value="default"/> <xs:enumeration value="preserve"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="base" type="xs:anyURI"/> <xs:attribute name="id" type="xs:ID"/> <xs:attributeGroup name="specialAttrs"> <xs:attribute ref="xml:base"/> <xs:attribute ref="xml:lang"/> <xs:attribute ref="xml:space"/> <xs:attribute ref="xml:id"/> </xs:attributeGroup> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.0/���������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020171�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.0/XMLSchema.xsd��������������������������������������������0000664�0000000�0000000�00000253444�14211403446�0022506�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='UTF-8'?> <!-- XML Schema schema for XML Schemas: Part 1: Structures --> <!-- Note this schema is NOT the normative structures schema. --> <!-- The prose copy in the structures REC is the normative --> <!-- version (which shouldn't differ from this one except for --> <!-- this comment and entity expansions, but just in case --> <!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" [ <!-- provide ID type information even for parsers which only read the internal subset --> <!ATTLIST xs:schema id ID #IMPLIED> <!ATTLIST xs:complexType id ID #IMPLIED> <!ATTLIST xs:complexContent id ID #IMPLIED> <!ATTLIST xs:simpleContent id ID #IMPLIED> <!ATTLIST xs:extension id ID #IMPLIED> <!ATTLIST xs:element id ID #IMPLIED> <!ATTLIST xs:group id ID #IMPLIED> <!ATTLIST xs:all id ID #IMPLIED> <!ATTLIST xs:choice id ID #IMPLIED> <!ATTLIST xs:sequence id ID #IMPLIED> <!ATTLIST xs:any id ID #IMPLIED> <!ATTLIST xs:anyAttribute id ID #IMPLIED> <!ATTLIST xs:attribute id ID #IMPLIED> <!ATTLIST xs:attributeGroup id ID #IMPLIED> <!ATTLIST xs:unique id ID #IMPLIED> <!ATTLIST xs:key id ID #IMPLIED> <!ATTLIST xs:keyref id ID #IMPLIED> <!ATTLIST xs:selector id ID #IMPLIED> <!ATTLIST xs:field id ID #IMPLIED> <!ATTLIST xs:include id ID #IMPLIED> <!ATTLIST xs:import id ID #IMPLIED> <!ATTLIST xs:redefine id ID #IMPLIED> <!ATTLIST xs:notation id ID #IMPLIED> <!-- keep this schema XML1.0 DTD valid --> <!ENTITY % schemaAttrs 'xmlns:hfp CDATA #IMPLIED'> <!ELEMENT hfp:hasFacet EMPTY> <!ATTLIST hfp:hasFacet name NMTOKEN #REQUIRED> <!ELEMENT hfp:hasProperty EMPTY> <!ATTLIST hfp:hasProperty name NMTOKEN #REQUIRED value CDATA #REQUIRED> <!-- Make sure that processors that do not read the external subset will know about the various IDs we declare --> <!ATTLIST xs:simpleType id ID #IMPLIED> <!ATTLIST xs:maxExclusive id ID #IMPLIED> <!ATTLIST xs:minExclusive id ID #IMPLIED> <!ATTLIST xs:maxInclusive id ID #IMPLIED> <!ATTLIST xs:minInclusive id ID #IMPLIED> <!ATTLIST xs:totalDigits id ID #IMPLIED> <!ATTLIST xs:fractionDigits id ID #IMPLIED> <!ATTLIST xs:length id ID #IMPLIED> <!ATTLIST xs:minLength id ID #IMPLIED> <!ATTLIST xs:maxLength id ID #IMPLIED> <!ATTLIST xs:enumeration id ID #IMPLIED> <!ATTLIST xs:pattern id ID #IMPLIED> <!ATTLIST xs:appinfo id ID #IMPLIED> <!ATTLIST xs:documentation id ID #IMPLIED> <!ATTLIST xs:list id ID #IMPLIED> <!ATTLIST xs:union id ID #IMPLIED> ]> <xs:schema targetNamespace="http://www.w3.org/2001/XMLSchema" blockDefault="#all" elementFormDefault="qualified" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="EN" xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"> <xs:annotation> <xs:documentation> Part 1 version: Id: structures.xsd,v 1.2 2004/01/15 11:34:25 ht Exp Part 2 version: Id: datatypes.xsd,v 1.3 2004/01/23 18:11:13 ht Exp </xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/2004/PER-xmlschema-1-20040318/structures.html"> The schema corresponding to this document is normative, with respect to the syntactic constraints it expresses in the XML Schema language. The documentation (within <documentation> elements) below, is not normative, but rather highlights important aspects of the W3C Recommendation of which this is a part</xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> The simpleType element and all of its members are defined towards the end of this schema document</xs:documentation> </xs:annotation> <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"> <xs:annotation> <xs:documentation> Get access to the xml: attribute groups for xml:lang as declared on 'schema' and 'documentation' below </xs:documentation> </xs:annotation> </xs:import> <xs:complexType name="openAttrs"> <xs:annotation> <xs:documentation> This type is extended by almost all schema types to allow attributes from other namespaces to be added to user schemas. </xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:anyType"> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="annotated"> <xs:annotation> <xs:documentation> This type is extended by all types which allow annotation other than <schema> itself </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="schemaTop"> <xs:annotation> <xs:documentation> This group is for the elements which occur freely at the top level of schemas. All of their types are based on the "annotated" type by extension.</xs:documentation> </xs:annotation> <xs:choice> <xs:group ref="xs:redefinable"/> <xs:element ref="xs:element"/> <xs:element ref="xs:attribute"/> <xs:element ref="xs:notation"/> </xs:choice> </xs:group> <xs:group name="redefinable"> <xs:annotation> <xs:documentation> This group is for the elements which can self-redefine (see <redefine> below).</xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:simpleType"/> <xs:element ref="xs:complexType"/> <xs:element ref="xs:group"/> <xs:element ref="xs:attributeGroup"/> </xs:choice> </xs:group> <xs:simpleType name="formChoice"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="qualified"/> <xs:enumeration value="unqualified"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="reducedDerivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="derivationSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {extension, restriction}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list itemType="xs:reducedDerivationControl"/> </xs:simpleType> </xs:union> </xs:simpleType> <xs:simpleType name="typeDerivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="fullDerivationSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {extension, restriction, list, union}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list itemType="xs:typeDerivationControl"/> </xs:simpleType> </xs:union> </xs:simpleType> <xs:element name="schema" id="schema"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-schema"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:include"/> <xs:element ref="xs:import"/> <xs:element ref="xs:redefine"/> <xs:element ref="xs:annotation"/> </xs:choice> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:group ref="xs:schemaTop"/> <xs:element ref="xs:annotation" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:sequence> <xs:attribute name="targetNamespace" type="xs:anyURI"/> <xs:attribute name="version" type="xs:token"/> <xs:attribute name="finalDefault" type="xs:fullDerivationSet" use="optional" default=""/> <xs:attribute name="blockDefault" type="xs:blockSet" use="optional" default=""/> <xs:attribute name="attributeFormDefault" type="xs:formChoice" use="optional" default="unqualified"/> <xs:attribute name="elementFormDefault" type="xs:formChoice" use="optional" default="unqualified"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute ref="xml:lang"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:key name="element"> <xs:selector xpath="xs:element"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="attribute"> <xs:selector xpath="xs:attribute"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="type"> <xs:selector xpath="xs:complexType|xs:simpleType"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="group"> <xs:selector xpath="xs:group"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="attributeGroup"> <xs:selector xpath="xs:attributeGroup"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="notation"> <xs:selector xpath="xs:notation"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="identityConstraint"> <xs:selector xpath=".//xs:key|.//xs:unique|.//xs:keyref"/> <xs:field xpath="@name"/> </xs:key> </xs:element> <xs:simpleType name="allNNI"> <xs:annotation><xs:documentation> for maxOccurs</xs:documentation></xs:annotation> <xs:union memberTypes="xs:nonNegativeInteger"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="unbounded"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> <xs:attributeGroup name="occurs"> <xs:annotation><xs:documentation> for all particles</xs:documentation></xs:annotation> <xs:attribute name="minOccurs" type="xs:nonNegativeInteger" use="optional" default="1"/> <xs:attribute name="maxOccurs" type="xs:allNNI" use="optional" default="1"/> </xs:attributeGroup> <xs:attributeGroup name="defRef"> <xs:annotation><xs:documentation> for element, group and attributeGroup, which both define and reference</xs:documentation></xs:annotation> <xs:attribute name="name" type="xs:NCName"/> <xs:attribute name="ref" type="xs:QName"/> </xs:attributeGroup> <xs:group name="typeDefParticle"> <xs:annotation> <xs:documentation> 'complexType' uses this</xs:documentation></xs:annotation> <xs:choice> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> </xs:choice> </xs:group> <xs:group name="nestedParticle"> <xs:choice> <xs:element name="element" type="xs:localElement"/> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> <xs:element ref="xs:any"/> </xs:choice> </xs:group> <xs:group name="particle"> <xs:choice> <xs:element name="element" type="xs:localElement"/> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> <xs:element ref="xs:any"/> </xs:choice> </xs:group> <xs:complexType name="attribute"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" minOccurs="0" type="xs:localSimpleType"/> </xs:sequence> <xs:attributeGroup ref="xs:defRef"/> <xs:attribute name="type" type="xs:QName"/> <xs:attribute name="use" use="optional" default="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="prohibited"/> <xs:enumeration value="optional"/> <xs:enumeration value="required"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="default" type="xs:string"/> <xs:attribute name="fixed" type="xs:string"/> <xs:attribute name="form" type="xs:formChoice"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelAttribute"> <xs:complexContent> <xs:restriction base="xs:attribute"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:element name="simpleType" minOccurs="0" type="xs:localSimpleType"/> </xs:sequence> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="form" use="prohibited"/> <xs:attribute name="use" use="prohibited"/> <xs:attribute name="name" use="required" type="xs:NCName"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:group name="attrDecls"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="attribute" type="xs:attribute"/> <xs:element name="attributeGroup" type="xs:attributeGroupRef"/> </xs:choice> <xs:element ref="xs:anyAttribute" minOccurs="0"/> </xs:sequence> </xs:group> <xs:element name="anyAttribute" type="xs:wildcard" id="anyAttribute"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-anyAttribute"/> </xs:annotation> </xs:element> <xs:group name="complexTypeModel"> <xs:choice> <xs:element ref="xs:simpleContent"/> <xs:element ref="xs:complexContent"/> <xs:sequence> <xs:annotation> <xs:documentation> This branch is short for <complexContent> <restriction base="xs:anyType"> ... </restriction> </complexContent></xs:documentation> </xs:annotation> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> </xs:choice> </xs:group> <xs:complexType name="complexType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:complexTypeModel"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Will be restricted to required or forbidden</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="mixed" type="xs:boolean" use="optional" default="false"> <xs:annotation> <xs:documentation> Not allowed if simpleContent child is chosen. May be overriden by setting on complexContent child.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="abstract" type="xs:boolean" use="optional" default="false"/> <xs:attribute name="final" type="xs:derivationSet"/> <xs:attribute name="block" type="xs:derivationSet"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelComplexType"> <xs:complexContent> <xs:restriction base="xs:complexType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:complexTypeModel"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localComplexType"> <xs:complexContent> <xs:restriction base="xs:complexType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:complexTypeModel"/> </xs:sequence> <xs:attribute name="name" use="prohibited"/> <xs:attribute name="abstract" use="prohibited"/> <xs:attribute name="final" use="prohibited"/> <xs:attribute name="block" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="restrictionType"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:choice minOccurs="0"> <xs:group ref="xs:typeDefParticle"/> <xs:group ref="xs:simpleRestrictionModel"/> </xs:choice> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:attribute name="base" type="xs:QName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="complexRestrictionType"> <xs:complexContent> <xs:restriction base="xs:restrictionType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:annotation> <xs:documentation>This choice is added simply to make this a valid restriction per the REC</xs:documentation> </xs:annotation> <xs:group ref="xs:typeDefParticle"/> </xs:choice> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="extensionType"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:attribute name="base" type="xs:QName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="complexContent" id="complexContent"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-complexContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:choice> <xs:element name="restriction" type="xs:complexRestrictionType"/> <xs:element name="extension" type="xs:extensionType"/> </xs:choice> <xs:attribute name="mixed" type="xs:boolean"> <xs:annotation> <xs:documentation> Overrides any setting on complexType parent.</xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="simpleRestrictionType"> <xs:complexContent> <xs:restriction base="xs:restrictionType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:annotation> <xs:documentation>This choice is added simply to make this a valid restriction per the REC</xs:documentation> </xs:annotation> <xs:group ref="xs:simpleRestrictionModel"/> </xs:choice> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="simpleExtensionType"> <xs:complexContent> <xs:restriction base="xs:extensionType"> <xs:sequence> <xs:annotation> <xs:documentation> No typeDefParticle group reference</xs:documentation> </xs:annotation> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleContent" id="simpleContent"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-simpleContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:choice> <xs:element name="restriction" type="xs:simpleRestrictionType"/> <xs:element name="extension" type="xs:simpleExtensionType"/> </xs:choice> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="complexType" type="xs:topLevelComplexType" id="complexType"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-complexType"/> </xs:annotation> </xs:element> <xs:simpleType name="blockSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {substitution, extension, restriction}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="substitution"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="element" abstract="true"> <xs:annotation> <xs:documentation> The element element can be used either at the top level to define an element-type binding globally, or within a content model to either reference a globally-defined element or type or declare an element-type binding locally. The ref form is not allowed at the top level.</xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attributeGroup ref="xs:defRef"/> <xs:attribute name="type" type="xs:QName"/> <xs:attribute name="substitutionGroup" type="xs:QName"/> <xs:attributeGroup ref="xs:occurs"/> <xs:attribute name="default" type="xs:string"/> <xs:attribute name="fixed" type="xs:string"/> <xs:attribute name="nillable" type="xs:boolean" use="optional" default="false"/> <xs:attribute name="abstract" type="xs:boolean" use="optional" default="false"/> <xs:attribute name="final" type="xs:derivationSet"/> <xs:attribute name="block" type="xs:blockSet"/> <xs:attribute name="form" type="xs:formChoice"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelElement"> <xs:complexContent> <xs:restriction base="xs:element"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="form" use="prohibited"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:attribute name="name" use="required" type="xs:NCName"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localElement"> <xs:complexContent> <xs:restriction base="xs:element"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="substitutionGroup" use="prohibited"/> <xs:attribute name="final" use="prohibited"/> <xs:attribute name="abstract" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="element" type="xs:topLevelElement" id="element"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-element"/> </xs:annotation> </xs:element> <xs:complexType name="group" abstract="true"> <xs:annotation> <xs:documentation> group type for explicit groups, named top-level groups and group references</xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:particle" minOccurs="0" maxOccurs="unbounded"/> <xs:attributeGroup ref="xs:defRef"/> <xs:attributeGroup ref="xs:occurs"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="realGroup"> <xs:complexContent> <xs:restriction base="xs:group"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="1"> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> </xs:choice> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="namedGroup"> <xs:complexContent> <xs:restriction base="xs:realGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="all"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:all"> <xs:group ref="xs:allModel"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="choice" type="xs:simpleExplicitGroup"/> <xs:element name="sequence" type="xs:simpleExplicitGroup"/> </xs:choice> </xs:sequence> <xs:attribute name="name" use="required" type="xs:NCName"/> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="groupRef"> <xs:complexContent> <xs:restriction base="xs:realGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="ref" use="required" type="xs:QName"/> <xs:attribute name="name" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="explicitGroup"> <xs:annotation> <xs:documentation> group type for the three kinds of group</xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:group"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:nestedParticle" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="prohibited"/> <xs:attribute name="ref" type="xs:QName" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="simpleExplicitGroup"> <xs:complexContent> <xs:restriction base="xs:explicitGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:nestedParticle" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:group name="allModel"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:annotation> <xs:documentation>This choice with min/max is here to avoid a pblm with the Elt:All/Choice/Seq Particle derivation constraint</xs:documentation> </xs:annotation> <xs:element name="element" type="xs:narrowMaxMin"/> </xs:choice> </xs:sequence> </xs:group> <xs:complexType name="narrowMaxMin"> <xs:annotation> <xs:documentation>restricted max/min</xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:localElement"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="minOccurs" use="optional" default="1"> <xs:simpleType> <xs:restriction base="xs:nonNegativeInteger"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="maxOccurs" use="optional" default="1"> <xs:simpleType> <xs:restriction base="xs:allNNI"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="all"> <xs:annotation> <xs:documentation> Only elements allowed inside</xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:explicitGroup"> <xs:group ref="xs:allModel"/> <xs:attribute name="minOccurs" use="optional" default="1"> <xs:simpleType> <xs:restriction base="xs:nonNegativeInteger"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="maxOccurs" use="optional" default="1"> <xs:simpleType> <xs:restriction base="xs:allNNI"> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="all" id="all" type="xs:all"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-all"/> </xs:annotation> </xs:element> <xs:element name="choice" type="xs:explicitGroup" id="choice"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-choice"/> </xs:annotation> </xs:element> <xs:element name="sequence" type="xs:explicitGroup" id="sequence"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-sequence"/> </xs:annotation> </xs:element> <xs:element name="group" type="xs:namedGroup" id="group"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-group"/> </xs:annotation> </xs:element> <xs:complexType name="wildcard"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="namespace" type="xs:namespaceList" use="optional" default="##any"/> <xs:attribute name="processContents" use="optional" default="strict"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="skip"/> <xs:enumeration value="lax"/> <xs:enumeration value="strict"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="any" id="any"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-any"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:wildcard"> <xs:attributeGroup ref="xs:occurs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> simple type for the value of the 'namespace' attr of 'any' and 'anyAttribute'</xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> Value is ##any - - any non-conflicting WFXML/attribute at all ##other - - any non-conflicting WFXML/attribute from namespace other than targetNS ##local - - any unqualified non-conflicting WFXML/attribute one or - - any non-conflicting WFXML/attribute from more URI the listed namespaces references (space separated) ##targetNamespace or ##local may appear in the above list, to refer to the targetNamespace of the enclosing schema or an absent targetNamespace respectively</xs:documentation> </xs:annotation> <xs:simpleType name="namespaceList"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##any"/> <xs:enumeration value="##other"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:union memberTypes="xs:anyURI"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##targetNamespace"/> <xs:enumeration value="##local"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:element name="attribute" type="xs:topLevelAttribute" id="attribute"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-attribute"/> </xs:annotation> </xs:element> <xs:complexType name="attributeGroup" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:attrDecls"/> <xs:attributeGroup ref="xs:defRef"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="namedAttributeGroup"> <xs:complexContent> <xs:restriction base="xs:attributeGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:attribute name="name" use="required" type="xs:NCName"/> <xs:attribute name="ref" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="attributeGroupRef"> <xs:complexContent> <xs:restriction base="xs:attributeGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="ref" use="required" type="xs:QName"/> <xs:attribute name="name" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="attributeGroup" type="xs:namedAttributeGroup" id="attributeGroup"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-attributeGroup"/> </xs:annotation> </xs:element> <xs:element name="include" id="include"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-include"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="schemaLocation" type="xs:anyURI" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="redefine" id="redefine"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-redefine"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:annotation"/> <xs:group ref="xs:redefinable"/> </xs:choice> <xs:attribute name="schemaLocation" type="xs:anyURI" use="required"/> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="import" id="import"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-import"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="namespace" type="xs:anyURI"/> <xs:attribute name="schemaLocation" type="xs:anyURI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="selector" id="selector"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-selector"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="xpath" use="required"> <xs:simpleType> <xs:annotation> <xs:documentation>A subset of XPath expressions for use in selectors</xs:documentation> <xs:documentation>A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:annotation> <xs:documentation>The following pattern is intended to allow XPath expressions per the following EBNF: Selector ::= Path ( '|' Path )* Path ::= ('.//')? Step ( '/' Step )* Step ::= '.' | NameTest NameTest ::= QName | '*' | NCName ':' '*' child:: is also allowed </xs:documentation> </xs:annotation> <!-- xmlschema mod: replaced by a regex check in XsdSelector <xs:pattern value="(\.//)?(((child::)?((\i\c*:)?(\i\c*|\*)))|\.)(/(((child::)?((\i\c*:)?(\i\c*|\*)))|\.))*(\|(\.//)?(((child::)?((\i\c*:)?(\i\c*|\*)))|\.)(/(((child::)?((\i\c*:)?(\i\c*|\*)))|\.))*)*"> </xs:pattern> --> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="field" id="field"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-field"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="xpath" use="required"> <xs:simpleType> <xs:annotation> <xs:documentation>A subset of XPath expressions for use in fields</xs:documentation> <xs:documentation>A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:annotation> <xs:documentation>The following pattern is intended to allow XPath expressions per the same EBNF as for selector, with the following change: Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest ) </xs:documentation> </xs:annotation> <!-- xmlschema mod: replaced by a regex check in XsdFieldSelector <xs:pattern value="(\.//)?((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)/)*((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)|((attribute::|@)((\i\c*:)?(\i\c*|\*))))(\|(\.//)?((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)/)*((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)|((attribute::|@)((\i\c*:)?(\i\c*|\*)))))*"> </xs:pattern> --> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="keybase"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element ref="xs:selector"/> <xs:element ref="xs:field" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="identityConstraint"> <xs:annotation> <xs:documentation>The three kinds of identity constraints, all with type of or derived from 'keybase'. </xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:unique"/> <xs:element ref="xs:key"/> <xs:element ref="xs:keyref"/> </xs:choice> </xs:group> <xs:element name="unique" type="xs:keybase" id="unique"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-unique"/> </xs:annotation> </xs:element> <xs:element name="key" type="xs:keybase" id="key"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-key"/> </xs:annotation> </xs:element> <xs:element name="keyref" id="keyref"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-keyref"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:keybase"> <xs:attribute name="refer" type="xs:QName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="notation" id="notation"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-notation"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:attribute name="public" type="xs:public"/> <xs:attribute name="system" type="xs:anyURI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:simpleType name="public"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> A public identifier, per ISO 8879</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"/> </xs:simpleType> <xs:element name="appinfo" id="appinfo"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-appinfo"/> </xs:annotation> <xs:complexType mixed="true"> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:any processContents="lax"/> </xs:sequence> <xs:attribute name="source" type="xs:anyURI"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> </xs:element> <xs:element name="documentation" id="documentation"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-documentation"/> </xs:annotation> <xs:complexType mixed="true"> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:any processContents="lax"/> </xs:sequence> <xs:attribute name="source" type="xs:anyURI"/> <xs:attribute ref="xml:lang"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> </xs:element> <xs:element name="annotation" id="annotation"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-1/#element-annotation"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:appinfo"/> <xs:element ref="xs:documentation"/> </xs:choice> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> notations for use within XML Schema schemas</xs:documentation> </xs:annotation> <xs:notation name="XMLSchemaStructures" public="structures" system="http://www.w3.org/2000/08/XMLSchema.xsd"/> <xs:notation name="XML" public="REC-xml-19980210" system="http://www.w3.org/TR/1998/REC-xml-19980210"/> <xs:complexType name="anyType" mixed="true"> <xs:annotation> <xs:documentation> Not the real urType, but as close an approximation as we can get in the XML representation</xs:documentation> </xs:annotation> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute processContents="lax"/> </xs:complexType> <xs:annotation> <xs:documentation> First the built-in primitive datatypes. These definitions are for information only, the real built-in definitions are magic. </xs:documentation> <xs:documentation> For each built-in datatype in this schema (both primitive and derived) can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the datatype For example, to address the int datatype, the URI is: http://www.w3.org/2001/XMLSchema#int Additionally, each facet definition element can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the facet For example, to address the maxInclusive facet, the URI is: http://www.w3.org/2001/XMLSchema#maxInclusive Additionally, each facet usage in a built-in datatype definition can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the datatype, followed by a period (".") followed by the name of the facet For example, to address the usage of the maxInclusive facet in the definition of int, the URI is: http://www.w3.org/2001/XMLSchema#int.maxInclusive </xs:documentation> </xs:annotation> <xs:simpleType name="string" id="string"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#string"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="preserve" id="string.preserve"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="boolean" id="boolean"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#boolean"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="boolean.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="float" id="float"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="total"/> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#float"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="float.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="double" id="double"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="total"/> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#double"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="double.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="decimal" id="decimal"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="totalDigits"/> <hfp:hasFacet name="fractionDigits"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="total"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#decimal"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="decimal.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="duration" id="duration"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#duration"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="duration.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="dateTime" id="dateTime"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#dateTime"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="dateTime.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="time" id="time"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#time"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="time.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date" id="date"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#date"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="date.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gYearMonth" id="gYearMonth"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gYearMonth"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="gYearMonth.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gYear" id="gYear"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gYear"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="gYear.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gMonthDay" id="gMonthDay"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gMonthDay"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="gMonthDay.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gDay" id="gDay"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gDay"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="gDay.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gMonth" id="gMonth"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gMonth"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="gMonth.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="hexBinary" id="hexBinary"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#binary"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="hexBinary.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="base64Binary" id="base64Binary"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#base64Binary"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="base64Binary.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="anyURI" id="anyURI"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#anyURI"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="anyURI.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="QName" id="QName"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#QName"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="QName.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NOTATION" id="NOTATION"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NOTATION"/> <xs:documentation> NOTATION cannot be used directly in a schema; rather a type must be derived from it by specifying at least one enumeration facet whose value is the name of a NOTATION declared in the schema. </xs:documentation> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="collapse" fixed="true" id="NOTATION.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:annotation> <xs:documentation> Now the derived primitive types </xs:documentation> </xs:annotation> <xs:simpleType name="normalizedString" id="normalizedString"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#normalizedString"/> </xs:annotation> <xs:restriction base="xs:string"> <xs:whiteSpace value="replace" id="normalizedString.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="token" id="token"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#token"/> </xs:annotation> <xs:restriction base="xs:normalizedString"> <xs:whiteSpace value="collapse" id="token.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="language" id="language"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#language"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*" id="language.pattern"> <xs:annotation> <xs:documentation source="http://www.ietf.org/rfc/rfc3066.txt"> pattern specifies the content of section 2.12 of XML 1.0e2 and RFC 3066 (Revised version of RFC 1766). </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="IDREFS" id="IDREFS"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#IDREFS"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:IDREF"/> </xs:simpleType> <xs:minLength value="1" id="IDREFS.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="ENTITIES" id="ENTITIES"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ENTITIES"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:ENTITY"/> </xs:simpleType> <xs:minLength value="1" id="ENTITIES.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NMTOKEN" id="NMTOKEN"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NMTOKEN"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="\c+" id="NMTOKEN.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml#NT-Nmtoken"> pattern matches production 7 from the XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="NMTOKENS" id="NMTOKENS"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NMTOKENS"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:NMTOKEN"/> </xs:simpleType> <xs:minLength value="1" id="NMTOKENS.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Name" id="Name"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#Name"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="\i\c*" id="Name.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml#NT-Name"> pattern matches production 5 from the XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="NCName" id="NCName"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NCName"/> </xs:annotation> <xs:restriction base="xs:Name"> <xs:pattern value="[\i-[:]][\c-[:]]*" id="NCName.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml-names/#NT-NCName"> pattern matches production 4 from the Namespaces in XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="ID" id="ID"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ID"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="IDREF" id="IDREF"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#IDREF"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="ENTITY" id="ENTITY"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ENTITY"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="integer" id="integer"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#integer"/> </xs:annotation> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="0" fixed="true" id="integer.fractionDigits"/> <xs:pattern value="[\-+]?[0-9]+"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="nonPositiveInteger" id="nonPositiveInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#nonPositiveInteger"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:maxInclusive value="0" id="nonPositiveInteger.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="negativeInteger" id="negativeInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#negativeInteger"/> </xs:annotation> <xs:restriction base="xs:nonPositiveInteger"> <xs:maxInclusive value="-1" id="negativeInteger.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="long" id="long"> <xs:annotation> <xs:appinfo> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#long"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:minInclusive value="-9223372036854775808" id="long.minInclusive"/> <xs:maxInclusive value="9223372036854775807" id="long.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="int" id="int"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#int"/> </xs:annotation> <xs:restriction base="xs:long"> <xs:minInclusive value="-2147483648" id="int.minInclusive"/> <xs:maxInclusive value="2147483647" id="int.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="short" id="short"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#short"/> </xs:annotation> <xs:restriction base="xs:int"> <xs:minInclusive value="-32768" id="short.minInclusive"/> <xs:maxInclusive value="32767" id="short.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="byte" id="byte"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#byte"/> </xs:annotation> <xs:restriction base="xs:short"> <xs:minInclusive value="-128" id="byte.minInclusive"/> <xs:maxInclusive value="127" id="byte.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="nonNegativeInteger" id="nonNegativeInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#nonNegativeInteger"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:minInclusive value="0" id="nonNegativeInteger.minInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedLong" id="unsignedLong"> <xs:annotation> <xs:appinfo> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedLong"/> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"> <xs:maxInclusive value="18446744073709551615" id="unsignedLong.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedInt" id="unsignedInt"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedInt"/> </xs:annotation> <xs:restriction base="xs:unsignedLong"> <xs:maxInclusive value="4294967295" id="unsignedInt.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedShort" id="unsignedShort"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedShort"/> </xs:annotation> <xs:restriction base="xs:unsignedInt"> <xs:maxInclusive value="65535" id="unsignedShort.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedByte" id="unsignedByte"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedByte"/> </xs:annotation> <xs:restriction base="xs:unsignedShort"> <xs:maxInclusive value="255" id="unsignedByte.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="positiveInteger" id="positiveInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#positiveInteger"/> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"> <xs:minInclusive value="1" id="positiveInteger.minInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="derivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="substitution"/> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:group name="simpleDerivation"> <xs:choice> <xs:element ref="xs:restriction"/> <xs:element ref="xs:list"/> <xs:element ref="xs:union"/> </xs:choice> </xs:group> <xs:simpleType name="simpleDerivationSet"> <xs:annotation> <xs:documentation> #all or (possibly empty) subset of {restriction, union, list} </xs:documentation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="list"/> <xs:enumeration value="union"/> <xs:enumeration value="restriction"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="simpleType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleDerivation"/> <xs:attribute name="final" type="xs:simpleDerivationSet"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Can be restricted to required or forbidden </xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" use="required" type="xs:NCName"> <xs:annotation> <xs:documentation> Required at the top level </xs:documentation> </xs:annotation> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" use="prohibited"> <xs:annotation> <xs:documentation> Forbidden when nested </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="final" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleType" type="xs:topLevelSimpleType" id="simpleType"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-simpleType"/> </xs:annotation> </xs:element> <xs:group name="facets"> <xs:annotation> <xs:documentation> We should use a substitution group for facets, but that's ruled out because it would allow users to add their own, which we're not ready for yet. </xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:minExclusive"/> <xs:element ref="xs:minInclusive"/> <xs:element ref="xs:maxExclusive"/> <xs:element ref="xs:maxInclusive"/> <xs:element ref="xs:totalDigits"/> <xs:element ref="xs:fractionDigits"/> <xs:element ref="xs:length"/> <xs:element ref="xs:minLength"/> <xs:element ref="xs:maxLength"/> <xs:element ref="xs:enumeration"/> <xs:element ref="xs:whiteSpace"/> <xs:element ref="xs:pattern"/> </xs:choice> </xs:group> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:group ref="xs:facets" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:element name="restriction" id="restriction"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-restriction"> base attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleRestrictionModel"/> <xs:attribute name="base" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="list" id="list"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-list"> itemType attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attribute name="itemType" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="union" id="union"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-union"> memberTypes attribute must be non-empty or there must be at least one simpleType child </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="memberTypes" use="optional"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="facet"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="value" use="required"/> <xs:attribute name="fixed" type="xs:boolean" use="optional" default="false"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="noFixedFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="fixed" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="minExclusive" id="minExclusive" type="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minExclusive"/> </xs:annotation> </xs:element> <xs:element name="minInclusive" id="minInclusive" type="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minInclusive"/> </xs:annotation> </xs:element> <xs:element name="maxExclusive" id="maxExclusive" type="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxExclusive"/> </xs:annotation> </xs:element> <xs:element name="maxInclusive" id="maxInclusive" type="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxInclusive"/> </xs:annotation> </xs:element> <xs:complexType name="numFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:nonNegativeInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="totalDigits" id="totalDigits"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-totalDigits"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:numFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:positiveInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="fractionDigits" id="fractionDigits" type="xs:numFacet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-fractionDigits"/> </xs:annotation> </xs:element> <xs:element name="length" id="length" type="xs:numFacet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-length"/> </xs:annotation> </xs:element> <xs:element name="minLength" id="minLength" type="xs:numFacet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minLength"/> </xs:annotation> </xs:element> <xs:element name="maxLength" id="maxLength" type="xs:numFacet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxLength"/> </xs:annotation> </xs:element> <xs:element name="enumeration" id="enumeration" type="xs:noFixedFacet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-enumeration"/> </xs:annotation> </xs:element> <xs:element name="whiteSpace" id="whiteSpace"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-whiteSpace"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="preserve"/> <xs:enumeration value="replace"/> <xs:enumeration value="collapse"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="pattern" id="pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-pattern"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:noFixedFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:string" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> </xs:schema> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.0/datatypes.xsd��������������������������������������������0000664�0000000�0000000�00000126415�14211403446�0022720�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<pre><![CDATA[<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" [ <!-- keep this schema XML1.0 DTD valid --> <!ENTITY % schemaAttrs 'xmlns:hfp CDATA #IMPLIED'> <!ELEMENT hfp:hasFacet EMPTY> <!ATTLIST hfp:hasFacet name NMTOKEN #REQUIRED> <!ELEMENT hfp:hasProperty EMPTY> <!ATTLIST hfp:hasProperty name NMTOKEN #REQUIRED value CDATA #REQUIRED> <!-- Make sure that processors that do not read the external subset will know about the various IDs we declare --> <!ATTLIST xs:simpleType id ID #IMPLIED> <!ATTLIST xs:maxExclusive id ID #IMPLIED> <!ATTLIST xs:minExclusive id ID #IMPLIED> <!ATTLIST xs:maxInclusive id ID #IMPLIED> <!ATTLIST xs:minInclusive id ID #IMPLIED> <!ATTLIST xs:totalDigits id ID #IMPLIED> <!ATTLIST xs:fractionDigits id ID #IMPLIED> <!ATTLIST xs:length id ID #IMPLIED> <!ATTLIST xs:minLength id ID #IMPLIED> <!ATTLIST xs:maxLength id ID #IMPLIED> <!ATTLIST xs:enumeration id ID #IMPLIED> <!ATTLIST xs:pattern id ID #IMPLIED> <!ATTLIST xs:appinfo id ID #IMPLIED> <!ATTLIST xs:documentation id ID #IMPLIED> <!ATTLIST xs:list id ID #IMPLIED> <!ATTLIST xs:union id ID #IMPLIED> ]> <?xml version='1.0'?> <xs:schema xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty" xmlns:xs="http://www.w3.org/2001/XMLSchema" blockDefault="#all" elementFormDefault="qualified" xml:lang="en" targetNamespace="http://www.w3.org/2001/XMLSchema" version="Id: datatypes.xsd,v 1.4 2004/05/29 10:26:33 ht Exp "> <xs:annotation> <xs:documentation source="../datatypes/datatypes-with-errata.html"> The schema corresponding to this document is normative, with respect to the syntactic constraints it expresses in the XML Schema language. The documentation (within <documentation> elements) below, is not normative, but rather highlights important aspects of the W3C Recommendation of which this is a part </xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> First the built-in primitive datatypes. These definitions are for information only, the real built-in definitions are magic. </xs:documentation> <xs:documentation> For each built-in datatype in this schema (both primitive and derived) can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the datatype For example, to address the int datatype, the URI is: http://www.w3.org/2001/XMLSchema#int Additionally, each facet definition element can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the facet For example, to address the maxInclusive facet, the URI is: http://www.w3.org/2001/XMLSchema#maxInclusive Additionally, each facet usage in a built-in datatype definition can be uniquely addressed via a URI constructed as follows: 1) the base URI is the URI of the XML Schema namespace 2) the fragment identifier is the name of the datatype, followed by a period (".") followed by the name of the facet For example, to address the usage of the maxInclusive facet in the definition of int, the URI is: http://www.w3.org/2001/XMLSchema#int.maxInclusive </xs:documentation> </xs:annotation> <xs:simpleType name="string" id="string"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#string"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace value="preserve" id="string.preserve"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="boolean" id="boolean"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#boolean"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="boolean.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="float" id="float"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#float"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="float.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="double" id="double"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#double"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="double.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="decimal" id="decimal"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="totalDigits"/> <hfp:hasFacet name="fractionDigits"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="total"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="true"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#decimal"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="decimal.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="duration" id="duration"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#duration"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="duration.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="dateTime" id="dateTime"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#dateTime"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="dateTime.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="time" id="time"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#time"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="time.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="date" id="date"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#date"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="date.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gYearMonth" id="gYearMonth"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gYearMonth"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="gYearMonth.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gYear" id="gYear"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gYear"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="gYear.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gMonthDay" id="gMonthDay"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gMonthDay"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="gMonthDay.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gDay" id="gDay"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gDay"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="gDay.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="gMonth" id="gMonth"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="maxInclusive"/> <hfp:hasFacet name="maxExclusive"/> <hfp:hasFacet name="minInclusive"/> <hfp:hasFacet name="minExclusive"/> <hfp:hasProperty name="ordered" value="partial"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#gMonth"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="gMonth.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="hexBinary" id="hexBinary"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#binary"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="hexBinary.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="base64Binary" id="base64Binary"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#base64Binary"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="base64Binary.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="anyURI" id="anyURI"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#anyURI"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="anyURI.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="QName" id="QName"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#QName"/> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="QName.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NOTATION" id="NOTATION"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="pattern"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NOTATION"/> <xs:documentation> NOTATION cannot be used directly in a schema; rather a type must be derived from it by specifying at least one enumeration facet whose value is the name of a NOTATION declared in the schema. </xs:documentation> </xs:annotation> <xs:restriction base="xs:anySimpleType"> <xs:whiteSpace fixed="true" value="collapse" id="NOTATION.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:annotation> <xs:documentation> Now the derived primitive types </xs:documentation> </xs:annotation> <xs:simpleType name="normalizedString" id="normalizedString"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#normalizedString"/> </xs:annotation> <xs:restriction base="xs:string"> <xs:whiteSpace value="replace" id="normalizedString.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="token" id="token"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#token"/> </xs:annotation> <xs:restriction base="xs:normalizedString"> <xs:whiteSpace value="collapse" id="token.whiteSpace"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="language" id="language"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#language"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*" id="language.pattern"> <xs:annotation> <xs:documentation source="http://www.ietf.org/rfc/rfc3066.txt"> pattern specifies the content of section 2.12 of XML 1.0e2 and RFC 3066 (Revised version of RFC 1766). </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="IDREFS" id="IDREFS"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#IDREFS"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:IDREF"/> </xs:simpleType> <xs:minLength value="1" id="IDREFS.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="ENTITIES" id="ENTITIES"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ENTITIES"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:ENTITY"/> </xs:simpleType> <xs:minLength value="1" id="ENTITIES.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NMTOKEN" id="NMTOKEN"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NMTOKEN"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="\c+" id="NMTOKEN.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml#NT-Nmtoken"> pattern matches production 7 from the XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="NMTOKENS" id="NMTOKENS"> <xs:annotation> <xs:appinfo> <hfp:hasFacet name="length"/> <hfp:hasFacet name="minLength"/> <hfp:hasFacet name="maxLength"/> <hfp:hasFacet name="enumeration"/> <hfp:hasFacet name="whiteSpace"/> <hfp:hasFacet name="pattern"/> <hfp:hasProperty name="ordered" value="false"/> <hfp:hasProperty name="bounded" value="false"/> <hfp:hasProperty name="cardinality" value="countably infinite"/> <hfp:hasProperty name="numeric" value="false"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NMTOKENS"/> </xs:annotation> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:NMTOKEN"/> </xs:simpleType> <xs:minLength value="1" id="NMTOKENS.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="Name" id="Name"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#Name"/> </xs:annotation> <xs:restriction base="xs:token"> <xs:pattern value="\i\c*" id="Name.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml#NT-Name"> pattern matches production 5 from the XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="NCName" id="NCName"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#NCName"/> </xs:annotation> <xs:restriction base="xs:Name"> <xs:pattern value="[\i-[:]][\c-[:]]*" id="NCName.pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/REC-xml-names/#NT-NCName"> pattern matches production 4 from the Namespaces in XML spec </xs:documentation> </xs:annotation> </xs:pattern> </xs:restriction> </xs:simpleType> <xs:simpleType name="ID" id="ID"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ID"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="IDREF" id="IDREF"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#IDREF"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="ENTITY" id="ENTITY"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#ENTITY"/> </xs:annotation> <xs:restriction base="xs:NCName"/> </xs:simpleType> <xs:simpleType name="integer" id="integer"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#integer"/> </xs:annotation> <xs:restriction base="xs:decimal"> <xs:fractionDigits fixed="true" value="0" id="integer.fractionDigits"/> <xs:pattern value="[\-+]?[0-9]+"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="nonPositiveInteger" id="nonPositiveInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#nonPositiveInteger"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:maxInclusive value="0" id="nonPositiveInteger.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="negativeInteger" id="negativeInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#negativeInteger"/> </xs:annotation> <xs:restriction base="xs:nonPositiveInteger"> <xs:maxInclusive value="-1" id="negativeInteger.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="long" id="long"> <xs:annotation> <xs:appinfo> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#long"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:minInclusive value="-9223372036854775808" id="long.minInclusive"/> <xs:maxInclusive value="9223372036854775807" id="long.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="int" id="int"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#int"/> </xs:annotation> <xs:restriction base="xs:long"> <xs:minInclusive value="-2147483648" id="int.minInclusive"/> <xs:maxInclusive value="2147483647" id="int.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="short" id="short"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#short"/> </xs:annotation> <xs:restriction base="xs:int"> <xs:minInclusive value="-32768" id="short.minInclusive"/> <xs:maxInclusive value="32767" id="short.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="byte" id="byte"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#byte"/> </xs:annotation> <xs:restriction base="xs:short"> <xs:minInclusive value="-128" id="byte.minInclusive"/> <xs:maxInclusive value="127" id="byte.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="nonNegativeInteger" id="nonNegativeInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#nonNegativeInteger"/> </xs:annotation> <xs:restriction base="xs:integer"> <xs:minInclusive value="0" id="nonNegativeInteger.minInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedLong" id="unsignedLong"> <xs:annotation> <xs:appinfo> <hfp:hasProperty name="bounded" value="true"/> <hfp:hasProperty name="cardinality" value="finite"/> </xs:appinfo> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedLong"/> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"> <xs:maxInclusive value="18446744073709551615" id="unsignedLong.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedInt" id="unsignedInt"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedInt"/> </xs:annotation> <xs:restriction base="xs:unsignedLong"> <xs:maxInclusive value="4294967295" id="unsignedInt.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedShort" id="unsignedShort"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedShort"/> </xs:annotation> <xs:restriction base="xs:unsignedInt"> <xs:maxInclusive value="65535" id="unsignedShort.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="unsignedByte" id="unsignedByte"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#unsignedByte"/> </xs:annotation> <xs:restriction base="xs:unsignedShort"> <xs:maxInclusive value="255" id="unsignedByte.maxInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="positiveInteger" id="positiveInteger"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#positiveInteger"/> </xs:annotation> <xs:restriction base="xs:nonNegativeInteger"> <xs:minInclusive value="1" id="positiveInteger.minInclusive"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="derivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="substitution"/> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:group name="simpleDerivation"> <xs:choice> <xs:element ref="xs:restriction"/> <xs:element ref="xs:list"/> <xs:element ref="xs:union"/> </xs:choice> </xs:group> <xs:simpleType name="simpleDerivationSet"> <xs:annotation> <xs:documentation> #all or (possibly empty) subset of {restriction, union, list} </xs:documentation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="list"/> <xs:enumeration value="union"/> <xs:enumeration value="restriction"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="simpleType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleDerivation"/> <xs:attribute name="final" type="xs:simpleDerivationSet"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Can be restricted to required or forbidden </xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"> <xs:annotation> <xs:documentation> Required at the top level </xs:documentation> </xs:annotation> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" use="prohibited"> <xs:annotation> <xs:documentation> Forbidden when nested </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="final" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleType" type="xs:topLevelSimpleType" id="simpleType"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-simpleType"/> </xs:annotation> </xs:element> <xs:group name="facets"> <xs:annotation> <xs:documentation> We should use a substitution group for facets, but that's ruled out because it would allow users to add their own, which we're not ready for yet. </xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:minExclusive"/> <xs:element ref="xs:minInclusive"/> <xs:element ref="xs:maxExclusive"/> <xs:element ref="xs:maxInclusive"/> <xs:element ref="xs:totalDigits"/> <xs:element ref="xs:fractionDigits"/> <xs:element ref="xs:length"/> <xs:element ref="xs:minLength"/> <xs:element ref="xs:maxLength"/> <xs:element ref="xs:enumeration"/> <xs:element ref="xs:whiteSpace"/> <xs:element ref="xs:pattern"/> </xs:choice> </xs:group> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:group ref="xs:facets" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:element name="restriction" id="restriction"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-restriction"> base attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleRestrictionModel"/> <xs:attribute name="base" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="list" id="list"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-list"> itemType attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attribute name="itemType" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="union" id="union"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-union"> memberTypes attribute must be non-empty or there must be at least one simpleType child </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="memberTypes" use="optional"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="facet"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="value" use="required"/> <xs:attribute name="fixed" type="xs:boolean" default="false" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="noFixedFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="fixed" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="minExclusive" type="xs:facet" id="minExclusive"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minExclusive"/> </xs:annotation> </xs:element> <xs:element name="minInclusive" type="xs:facet" id="minInclusive"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minInclusive"/> </xs:annotation> </xs:element> <xs:element name="maxExclusive" type="xs:facet" id="maxExclusive"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxExclusive"/> </xs:annotation> </xs:element> <xs:element name="maxInclusive" type="xs:facet" id="maxInclusive"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxInclusive"/> </xs:annotation> </xs:element> <xs:complexType name="numFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:nonNegativeInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="totalDigits" id="totalDigits"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-totalDigits"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:numFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:positiveInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="fractionDigits" type="xs:numFacet" id="fractionDigits"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-fractionDigits"/> </xs:annotation> </xs:element> <xs:element name="length" type="xs:numFacet" id="length"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-length"/> </xs:annotation> </xs:element> <xs:element name="minLength" type="xs:numFacet" id="minLength"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-minLength"/> </xs:annotation> </xs:element> <xs:element name="maxLength" type="xs:numFacet" id="maxLength"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-maxLength"/> </xs:annotation> </xs:element> <xs:element name="enumeration" type="xs:noFixedFacet" id="enumeration"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-enumeration"/> </xs:annotation> </xs:element> <xs:element name="whiteSpace" id="whiteSpace"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-whiteSpace"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="preserve"/> <xs:enumeration value="replace"/> <xs:enumeration value="collapse"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="pattern" id="pattern"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema-2/#element-pattern"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:noFixedFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:string" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> </xs:schema> ]]></pre> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.1/���������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0020172�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.1/XMLSchema.xsd��������������������������������������������0000664�0000000�0000000�00000213140�14211403446�0022474�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XSD 1.1//EN" "XMLSchema.dtd" [ <!-- provide ID type information even for parsers which only read the internal subset --> <!ATTLIST xs:schema id ID #IMPLIED> <!ATTLIST xs:complexType id ID #IMPLIED> <!ATTLIST xs:complexContent id ID #IMPLIED> <!ATTLIST xs:simpleContent id ID #IMPLIED> <!ATTLIST xs:extension id ID #IMPLIED> <!ATTLIST xs:element id ID #IMPLIED> <!ATTLIST xs:group id ID #IMPLIED> <!ATTLIST xs:all id ID #IMPLIED> <!ATTLIST xs:choice id ID #IMPLIED> <!ATTLIST xs:sequence id ID #IMPLIED> <!ATTLIST xs:any id ID #IMPLIED> <!ATTLIST xs:anyAttribute id ID #IMPLIED> <!ATTLIST xs:attribute id ID #IMPLIED> <!ATTLIST xs:attributeGroup id ID #IMPLIED> <!ATTLIST xs:unique id ID #IMPLIED> <!ATTLIST xs:key id ID #IMPLIED> <!ATTLIST xs:keyref id ID #IMPLIED> <!ATTLIST xs:selector id ID #IMPLIED> <!ATTLIST xs:field id ID #IMPLIED> <!ATTLIST xs:assert id ID #IMPLIED> <!ATTLIST xs:include id ID #IMPLIED> <!ATTLIST xs:import id ID #IMPLIED> <!ATTLIST xs:redefine id ID #IMPLIED> <!ATTLIST xs:override id ID #IMPLIED> <!ATTLIST xs:notation id ID #IMPLIED> <!-- Make sure that processors that do not read the external subset will know about the various IDs we declare --> <!ATTLIST xs:simpleType id ID #IMPLIED> <!ATTLIST xs:maxExclusive id ID #IMPLIED> <!ATTLIST xs:minExclusive id ID #IMPLIED> <!ATTLIST xs:maxInclusive id ID #IMPLIED> <!ATTLIST xs:minInclusive id ID #IMPLIED> <!ATTLIST xs:totalDigits id ID #IMPLIED> <!ATTLIST xs:fractionDigits id ID #IMPLIED> <!ATTLIST xs:length id ID #IMPLIED> <!ATTLIST xs:minLength id ID #IMPLIED> <!ATTLIST xs:maxLength id ID #IMPLIED> <!ATTLIST xs:enumeration id ID #IMPLIED> <!ATTLIST xs:pattern id ID #IMPLIED> <!ATTLIST xs:assertion id ID #IMPLIED> <!ATTLIST xs:explicitTimezone id ID #IMPLIED> <!ATTLIST xs:appinfo id ID #IMPLIED> <!ATTLIST xs:documentation id ID #IMPLIED> <!ATTLIST xs:list id ID #IMPLIED> <!ATTLIST xs:union id ID #IMPLIED> ]> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xml:lang="EN" targetNamespace="http://www.w3.org/2001/XMLSchema" version="1.0"> <xs:annotation> <xs:documentation> Part 1 version: structures.xsd (rec-20120405) Part 2 version: datatypes.xsd (rec-20120405) </xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation source="../structures/structures.html"> The schema corresponding to this document is normative, with respect to the syntactic constraints it expresses in the XML Schema Definition Language. The documentation (within 'documentation' elements) below, is not normative, but rather highlights important aspects of the W3C Recommendation of which this is a part. See below (at the bottom of this document) for information about the revision and namespace-versioning policy governing this schema document. </xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> The simpleType element and all of its members are defined towards the end of this schema document.</xs:documentation> </xs:annotation> <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"> <xs:annotation> <xs:documentation> Get access to the xml: attribute groups for xml:lang as declared on 'schema' and 'documentation' below </xs:documentation> </xs:annotation> </xs:import> <xs:complexType name="openAttrs"> <xs:annotation> <xs:documentation> This type is extended by almost all schema types to allow attributes from other namespaces to be added to user schemas. </xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:anyType"> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="annotated"> <xs:annotation> <xs:documentation> This type is extended by all types which allow annotation other than <schema> itself </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="composition"> <xs:choice> <xs:element ref="xs:include"/> <xs:element ref="xs:import"/> <xs:element ref="xs:redefine"/> <xs:element ref="xs:override"/> <xs:element ref="xs:annotation"/> </xs:choice> </xs:group> <xs:group name="schemaTop"> <xs:annotation> <xs:documentation> This group is for the elements which occur freely at the top level of schemas. All of their types are based on the "annotated" type by extension.</xs:documentation> </xs:annotation> <xs:choice> <xs:group ref="xs:redefinable"/> <xs:element ref="xs:element"/> <xs:element ref="xs:attribute"/> <xs:element ref="xs:notation"/> </xs:choice> </xs:group> <xs:group name="redefinable"> <xs:annotation> <xs:documentation> This group is for the elements which can self-redefine (see <redefine> below).</xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:simpleType"/> <xs:element ref="xs:complexType"/> <xs:element ref="xs:group"/> <xs:element ref="xs:attributeGroup"/> </xs:choice> </xs:group> <xs:simpleType name="formChoice"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="qualified"/> <xs:enumeration value="unqualified"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="reducedDerivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="derivationSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {extension, restriction}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list itemType="xs:reducedDerivationControl"/> </xs:simpleType> </xs:union> </xs:simpleType> <xs:simpleType name="typeDerivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="fullDerivationSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {extension, restriction, list, union}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list itemType="xs:typeDerivationControl"/> </xs:simpleType> </xs:union> </xs:simpleType> <xs:element name="schema" id="schema"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-schema"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:group ref="xs:composition" minOccurs="0" maxOccurs="unbounded"/> <xs:sequence minOccurs="0"> <xs:element ref="xs:defaultOpenContent"/> <xs:element ref="xs:annotation" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:group ref="xs:schemaTop"/> <xs:element ref="xs:annotation" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:sequence> <xs:attribute name="targetNamespace" type="xs:anyURI"/> <xs:attribute name="version" type="xs:token"/> <xs:attribute name="finalDefault" type="xs:fullDerivationSet" default="" use="optional"/> <xs:attribute name="blockDefault" type="xs:blockSet" default="" use="optional"/> <xs:attribute name="attributeFormDefault" type="xs:formChoice" default="unqualified" use="optional"/> <xs:attribute name="elementFormDefault" type="xs:formChoice" default="unqualified" use="optional"/> <xs:attribute name="defaultAttributes" type="xs:QName"/> <xs:attribute name="xpathDefaultNamespace" type="xs:xpathDefaultNamespace" default="##local" use="optional"/> <xs:attribute name="id" type="xs:ID"/> <xs:attribute ref="xml:lang"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:key name="element"> <xs:selector xpath="xs:element"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="attribute"> <xs:selector xpath="xs:attribute"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="type"> <xs:selector xpath="xs:complexType|xs:simpleType"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="group"> <xs:selector xpath="xs:group"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="attributeGroup"> <xs:selector xpath="xs:attributeGroup"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="notation"> <xs:selector xpath="xs:notation"/> <xs:field xpath="@name"/> </xs:key> <xs:key name="identityConstraint"> <xs:selector xpath=".//xs:key|.//xs:unique|.//xs:keyref"/> <xs:field xpath="@name"/> </xs:key> </xs:element> <xs:simpleType name="allNNI"> <xs:annotation> <xs:documentation> for maxOccurs</xs:documentation> </xs:annotation> <xs:union memberTypes="xs:nonNegativeInteger"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="unbounded"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> <xs:attributeGroup name="occurs"> <xs:annotation> <xs:documentation> for all particles</xs:documentation> </xs:annotation> <xs:attribute name="minOccurs" type="xs:nonNegativeInteger" default="1" use="optional"/> <xs:attribute name="maxOccurs" type="xs:allNNI" default="1" use="optional"/> </xs:attributeGroup> <xs:attributeGroup name="defRef"> <xs:annotation> <xs:documentation> for element, group and attributeGroup, which both define and reference</xs:documentation> </xs:annotation> <xs:attribute name="name" type="xs:NCName"/> <xs:attribute name="ref" type="xs:QName"/> </xs:attributeGroup> <xs:group name="typeDefParticle"> <xs:annotation> <xs:documentation> 'complexType' uses this</xs:documentation> </xs:annotation> <xs:choice> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> </xs:choice> </xs:group> <xs:group name="nestedParticle"> <xs:choice> <xs:element name="element" type="xs:localElement"/> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> <xs:element ref="xs:any"/> </xs:choice> </xs:group> <xs:group name="particle"> <xs:choice> <xs:element name="element" type="xs:localElement"/> <xs:element name="group" type="xs:groupRef"/> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> <xs:element ref="xs:any"/> </xs:choice> </xs:group> <xs:complexType name="attribute"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attributeGroup ref="xs:defRef"/> <xs:attribute name="type" type="xs:QName"/> <xs:attribute name="use" default="optional" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="prohibited"/> <xs:enumeration value="optional"/> <xs:enumeration value="required"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="default" type="xs:string"/> <xs:attribute name="fixed" type="xs:string"/> <xs:attribute name="form" type="xs:formChoice"/> <xs:attribute name="targetNamespace" type="xs:anyURI"/> <xs:attribute name="inheritable" type="xs:boolean"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelAttribute"> <xs:complexContent> <xs:restriction base="xs:attribute"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="form" use="prohibited"/> <xs:attribute name="use" use="prohibited"/> <xs:attribute name="targetNamespace" use="prohibited"/> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:attribute name="inheritable" type="xs:boolean"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:group name="attrDecls"> <xs:sequence> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="attribute" type="xs:attribute"/> <xs:element name="attributeGroup" type="xs:attributeGroupRef"/> </xs:choice> <xs:element ref="xs:anyAttribute" minOccurs="0"/> </xs:sequence> </xs:group> <xs:element name="anyAttribute" id="anyAttribute"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-anyAttribute"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:wildcard"> <xs:attribute name="notQName" type="xs:qnameListA" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:group name="assertions"> <xs:sequence> <xs:element name="assert" type="xs:assertion" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:group> <xs:complexType name="assertion"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="test" type="xs:string"/> <xs:attribute name="xpathDefaultNamespace" type="xs:xpathDefaultNamespace"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="complexTypeModel"> <xs:choice> <xs:element ref="xs:simpleContent"/> <xs:element ref="xs:complexContent"/> <xs:sequence> <xs:annotation> <xs:documentation> This branch is short for <complexContent> <restriction base="xs:anyType"> ... </restriction> </complexContent></xs:documentation> </xs:annotation> <xs:element ref="xs:openContent" minOccurs="0"/> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> </xs:choice> </xs:group> <xs:complexType name="complexType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:complexTypeModel"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Will be restricted to required or prohibited</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="mixed" type="xs:boolean" use="optional"> <xs:annotation> <xs:documentation> Not allowed if simpleContent child is chosen. May be overridden by setting on complexContent child.</xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="abstract" type="xs:boolean" default="false" use="optional"/> <xs:attribute name="final" type="xs:derivationSet"/> <xs:attribute name="block" type="xs:derivationSet"/> <xs:attribute name="defaultAttributesApply" type="xs:boolean" default="true" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelComplexType"> <xs:complexContent> <xs:restriction base="xs:complexType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:complexTypeModel"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localComplexType"> <xs:complexContent> <xs:restriction base="xs:complexType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:complexTypeModel"/> </xs:sequence> <xs:attribute name="name" use="prohibited"/> <xs:attribute name="abstract" use="prohibited"/> <xs:attribute name="final" use="prohibited"/> <xs:attribute name="block" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="restrictionType"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:choice minOccurs="0"> <xs:sequence> <xs:element ref="xs:openContent" minOccurs="0"/> <xs:group ref="xs:typeDefParticle"/> </xs:sequence> <xs:group ref="xs:simpleRestrictionModel"/> </xs:choice> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> <xs:attribute name="base" type="xs:QName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="complexRestrictionType"> <xs:complexContent> <xs:restriction base="xs:restrictionType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:annotation> <xs:documentation>This choice is added simply to make this a valid restriction per the REC</xs:documentation> </xs:annotation> <xs:sequence> <xs:element ref="xs:openContent" minOccurs="0"/> <xs:group ref="xs:typeDefParticle"/> </xs:sequence> </xs:choice> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="extensionType"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element ref="xs:openContent" minOccurs="0"/> <xs:group ref="xs:typeDefParticle" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> <xs:attribute name="base" type="xs:QName" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="complexContent" id="complexContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-complexContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:choice> <xs:element name="restriction" type="xs:complexRestrictionType"/> <xs:element name="extension" type="xs:extensionType"/> </xs:choice> <xs:attribute name="mixed" type="xs:boolean"> <xs:annotation> <xs:documentation> Overrides any setting on complexType parent.</xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="openContent" id="openContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-openContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="any" minOccurs="0" type="xs:wildcard"/> </xs:sequence> <xs:attribute name="mode" default="interleave" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="none"/> <xs:enumeration value="interleave"/> <xs:enumeration value="suffix"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="defaultOpenContent" id="defaultOpenContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-defaultOpenContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="any" type="xs:wildcard"/> </xs:sequence> <xs:attribute name="appliesToEmpty" type="xs:boolean" default="false" use="optional"/> <xs:attribute name="mode" default="interleave" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="interleave"/> <xs:enumeration value="suffix"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="simpleRestrictionType"> <xs:complexContent> <xs:restriction base="xs:restrictionType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:annotation> <xs:documentation>This choice is added simply to make this a valid restriction per the REC</xs:documentation> </xs:annotation> <xs:group ref="xs:simpleRestrictionModel"/> </xs:choice> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="simpleExtensionType"> <xs:complexContent> <xs:restriction base="xs:extensionType"> <xs:sequence> <xs:annotation> <xs:documentation> No typeDefParticle group reference</xs:documentation> </xs:annotation> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> <xs:group ref="xs:assertions"/> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleContent" id="simpleContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-simpleContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:choice> <xs:element name="restriction" type="xs:simpleRestrictionType"/> <xs:element name="extension" type="xs:simpleExtensionType"/> </xs:choice> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="complexType" type="xs:topLevelComplexType" id="complexType"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-complexType"/> </xs:annotation> </xs:element> <xs:simpleType name="blockSet"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> #all or (possibly empty) subset of {substitution, extension, restriction}</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="substitution"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="element" abstract="true"> <xs:annotation> <xs:documentation> The element element can be used either at the top level to define an element-type binding globally, or within a content model to either reference a globally-defined element or type or declare an element-type binding locally. The ref form is not allowed at the top level.</xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:element name="alternative" type="xs:altType" minOccurs="0" maxOccurs="unbounded"/> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attributeGroup ref="xs:defRef"/> <xs:attribute name="type" type="xs:QName"/> <xs:attribute name="substitutionGroup"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> <xs:attributeGroup ref="xs:occurs"/> <xs:attribute name="default" type="xs:string"/> <xs:attribute name="fixed" type="xs:string"/> <xs:attribute name="nillable" type="xs:boolean" use="optional"/> <xs:attribute name="abstract" type="xs:boolean" default="false" use="optional"/> <xs:attribute name="final" type="xs:derivationSet"/> <xs:attribute name="block" type="xs:blockSet"/> <xs:attribute name="form" type="xs:formChoice"/> <xs:attribute name="targetNamespace" type="xs:anyURI"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelElement"> <xs:complexContent> <xs:restriction base="xs:element"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:element name="alternative" type="xs:altType" minOccurs="0" maxOccurs="unbounded"/> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="form" use="prohibited"/> <xs:attribute name="targetNamespace" use="prohibited"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localElement"> <xs:complexContent> <xs:restriction base="xs:element"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:element name="alternative" type="xs:altType" minOccurs="0" maxOccurs="unbounded"/> <xs:group ref="xs:identityConstraint" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="substitutionGroup" use="prohibited"/> <xs:attribute name="final" use="prohibited"/> <xs:attribute name="abstract" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="element" type="xs:topLevelElement" id="element"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-element"/> </xs:annotation> </xs:element> <xs:complexType name="altType"> <xs:annotation> <xs:documentation> This type is used for 'alternative' elements. </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:choice minOccurs="0"> <xs:element name="simpleType" type="xs:localSimpleType"/> <xs:element name="complexType" type="xs:localComplexType"/> </xs:choice> <xs:attribute name="test" type="xs:string" use="optional"/> <xs:attribute name="type" type="xs:QName" use="optional"/> <xs:attribute name="xpathDefaultNamespace" type="xs:xpathDefaultNamespace"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="group" abstract="true"> <xs:annotation> <xs:documentation> group type for explicit groups, named top-level groups and group references</xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:particle" minOccurs="0" maxOccurs="unbounded"/> <xs:attributeGroup ref="xs:defRef"/> <xs:attributeGroup ref="xs:occurs"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="realGroup"> <xs:complexContent> <xs:restriction base="xs:group"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="1"> <xs:element ref="xs:all"/> <xs:element ref="xs:choice"/> <xs:element ref="xs:sequence"/> </xs:choice> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="namedGroup"> <xs:complexContent> <xs:restriction base="xs:realGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="1" maxOccurs="1"> <xs:element name="all"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:all"> <xs:group ref="xs:allModel"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="choice" type="xs:simpleExplicitGroup"/> <xs:element name="sequence" type="xs:simpleExplicitGroup"/> </xs:choice> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:attribute name="ref" use="prohibited"/> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="groupRef"> <xs:complexContent> <xs:restriction base="xs:realGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="ref" type="xs:QName" use="required"/> <xs:attribute name="name" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="explicitGroup"> <xs:annotation> <xs:documentation> group type for the three kinds of group</xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:group"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:nestedParticle" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="name" use="prohibited"/> <xs:attribute name="ref" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="simpleExplicitGroup"> <xs:complexContent> <xs:restriction base="xs:explicitGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:nestedParticle" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="minOccurs" use="prohibited"/> <xs:attribute name="maxOccurs" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:group name="allModel"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:annotation> <xs:documentation>This choice with min/max is here to avoid a pblm with the Elt:All/Choice/Seq Particle derivation constraint</xs:documentation> </xs:annotation> <xs:element name="element" type="xs:localElement"/> <xs:element ref="xs:any"/> <xs:element name="group"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:groupRef"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="minOccurs" fixed="1" type="xs:nonNegativeInteger"/> <xs:attribute name="maxOccurs" fixed="1" type="xs:nonNegativeInteger"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> </xs:choice> </xs:sequence> </xs:group> <xs:complexType name="all"> <xs:annotation> <xs:documentation> Only elements allowed inside</xs:documentation> </xs:annotation> <xs:complexContent> <xs:restriction base="xs:explicitGroup"> <xs:group ref="xs:allModel"/> <xs:attribute name="minOccurs" default="1" use="optional"> <xs:simpleType> <xs:restriction base="xs:nonNegativeInteger"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="maxOccurs" default="1" use="optional"> <xs:simpleType> <xs:restriction base="xs:allNNI"> <xs:enumeration value="0"/> <xs:enumeration value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="all" type="xs:all" id="all"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-all"/> </xs:annotation> </xs:element> <xs:element name="choice" type="xs:explicitGroup" id="choice"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-choice"/> </xs:annotation> </xs:element> <xs:element name="sequence" type="xs:explicitGroup" id="sequence"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-sequence"/> </xs:annotation> </xs:element> <xs:element name="group" type="xs:namedGroup" id="group"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-group"/> </xs:annotation> </xs:element> <xs:attributeGroup name="anyAttrGroup"> <xs:attribute name="namespace" type="xs:namespaceList" use="optional"/> <xs:attribute name="notNamespace" use="optional"> <xs:simpleType> <xs:restriction base="xs:basicNamespaceList"> <xs:minLength value="1"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="processContents" default="strict" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="skip"/> <xs:enumeration value="lax"/> <xs:enumeration value="strict"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:attributeGroup> <xs:complexType name="wildcard"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attributeGroup ref="xs:anyAttrGroup"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="any" id="any"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-any"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:wildcard"> <xs:attribute name="notQName" type="xs:qnameList" use="optional"/> <xs:attributeGroup ref="xs:occurs"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> simple type for the value of the 'namespace' attr of 'any' and 'anyAttribute'</xs:documentation> </xs:annotation> <xs:annotation> <xs:documentation> Value is ##any - - any non-conflicting WFXML/attribute at all ##other - - any non-conflicting WFXML/attribute from namespace other than targetNS ##local - - any unqualified non-conflicting WFXML/attribute one or - - any non-conflicting WFXML/attribute from more URI the listed namespaces references (space separated) ##targetNamespace or ##local may appear in the above list, to refer to the targetNamespace of the enclosing schema or an absent targetNamespace respectively</xs:documentation> </xs:annotation> <xs:simpleType name="namespaceList"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union memberTypes="xs:specialNamespaceList xs:basicNamespaceList" /> </xs:simpleType> <xs:simpleType name="basicNamespaceList"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:list> <xs:simpleType> <xs:union memberTypes="xs:anyURI"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##targetNamespace"/> <xs:enumeration value="##local"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> </xs:list> </xs:simpleType> <xs:simpleType name="specialNamespaceList"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"> <xs:enumeration value="##any"/> <xs:enumeration value="##other"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="qnameList"> <xs:annotation> <xs:documentation> A utility type, not for public use </xs:documentation> </xs:annotation> <xs:list> <xs:simpleType> <xs:union memberTypes="xs:QName"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##defined"/> <xs:enumeration value="##definedSibling"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> </xs:list> </xs:simpleType> <xs:simpleType name="qnameListA"> <xs:annotation> <xs:documentation> A utility type, not for public use </xs:documentation> </xs:annotation> <xs:list> <xs:simpleType> <xs:union memberTypes="xs:QName"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##defined"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> </xs:list> </xs:simpleType> <xs:simpleType name="xpathDefaultNamespace"> <xs:union memberTypes="xs:anyURI"> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="##defaultNamespace"/> <xs:enumeration value="##targetNamespace"/> <xs:enumeration value="##local"/> </xs:restriction> </xs:simpleType> </xs:union> </xs:simpleType> <xs:element name="attribute" type="xs:topLevelAttribute" id="attribute"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-attribute"/> </xs:annotation> </xs:element> <xs:complexType name="attributeGroup" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:attrDecls"/> <xs:attributeGroup ref="xs:defRef"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="namedAttributeGroup"> <xs:complexContent> <xs:restriction base="xs:attributeGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:attrDecls"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:attribute name="ref" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="attributeGroupRef"> <xs:complexContent> <xs:restriction base="xs:attributeGroup"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="ref" type="xs:QName" use="required"/> <xs:attribute name="name" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="attributeGroup" type="xs:namedAttributeGroup" id="attributeGroup"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-attributeGroup"/> </xs:annotation> </xs:element> <xs:element name="include" id="include"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-include"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="schemaLocation" type="xs:anyURI" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="redefine" id="redefine"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-redefine"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:annotation"/> <xs:group ref="xs:redefinable"/> </xs:choice> <xs:attribute name="schemaLocation" type="xs:anyURI" use="required"/> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="override" id="override"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-override"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:schemaTop" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="schemaLocation" type="xs:anyURI" use="required"/> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="import" id="import"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-import"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="namespace" type="xs:anyURI"/> <xs:attribute name="schemaLocation" type="xs:anyURI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="selector" id="selector"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-selector"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="xpath" use="required"> <xs:simpleType> <xs:annotation> <xs:documentation>A subset of XPath expressions for use in selectors</xs:documentation> <xs:documentation>A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"/> </xs:simpleType> </xs:attribute> <xs:attribute name="xpathDefaultNamespace" type="xs:xpathDefaultNamespace"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="field" id="field"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-field"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="xpath" use="required"> <xs:simpleType> <xs:annotation> <xs:documentation>A subset of XPath expressions for use in fields</xs:documentation> <xs:documentation>A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"/> </xs:simpleType> </xs:attribute> <xs:attribute name="xpathDefaultNamespace" type="xs:xpathDefaultNamespace"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="keybase"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence minOccurs="0"> <xs:element ref="xs:selector"/> <xs:element ref="xs:field" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName"/> <xs:attribute name="ref" type="xs:QName"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:group name="identityConstraint"> <xs:annotation> <xs:documentation>The three kinds of identity constraints, all with type of or derived from 'keybase'. </xs:documentation> </xs:annotation> <xs:choice> <xs:element ref="xs:unique"/> <xs:element ref="xs:key"/> <xs:element ref="xs:keyref"/> </xs:choice> </xs:group> <xs:element name="unique" type="xs:keybase" id="unique"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-unique"/> </xs:annotation> </xs:element> <xs:element name="key" type="xs:keybase" id="key"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-key"/> </xs:annotation> </xs:element> <xs:element name="keyref" id="keyref"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-keyref"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:keybase"> <xs:attribute name="refer" type="xs:QName"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="notation" id="notation"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-notation"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="name" type="xs:NCName" use="required"/> <xs:attribute name="public" type="xs:public"/> <xs:attribute name="system" type="xs:anyURI"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:simpleType name="public"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> <xs:documentation> A public identifier, per ISO 8879</xs:documentation> </xs:annotation> <xs:restriction base="xs:token"/> </xs:simpleType> <xs:element name="appinfo" id="appinfo"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-appinfo"/> </xs:annotation> <xs:complexType mixed="true"> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:any processContents="lax"/> </xs:sequence> <xs:attribute name="source" type="xs:anyURI"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> </xs:element> <xs:element name="documentation" id="documentation"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-documentation"/> </xs:annotation> <xs:complexType mixed="true"> <xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:any processContents="lax"/> </xs:sequence> <xs:attribute name="source" type="xs:anyURI"/> <xs:attribute ref="xml:lang"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:complexType> </xs:element> <xs:element name="annotation" id="annotation"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-annotation"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:openAttrs"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:appinfo"/> <xs:element ref="xs:documentation"/> </xs:choice> <xs:attribute name="id" type="xs:ID"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> notations for use within schema documents</xs:documentation> </xs:annotation> <xs:notation name="XMLSchemaStructures" public="structures" system="http://www.w3.org/2000/08/XMLSchema.xsd"/> <xs:notation name="XML" public="REC-xml-19980210" system="http://www.w3.org/TR/1998/REC-xml-19980210"/> <xs:complexType name="anyType" mixed="true"> <xs:annotation> <xs:documentation> Not the real urType, but as close an approximation as we can get in the XML representation</xs:documentation> </xs:annotation> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:anyAttribute processContents="lax"/> </xs:complexType> <xs:annotation> <xs:documentation> In keeping with the XML Schema WG's standard versioning policy, the material in this schema document will persist at the URI http://www.w3.org/2012/04/XMLSchema.xsd. At the date of issue it can also be found at the URI http://www.w3.org/2009/XMLSchema/XMLSchema.xsd. The schema document at that URI may however change in the future, in order to remain compatible with the latest version of XSD and its namespace. In other words, if XSD or the XML Schema namespace change, the version of this document at http://www.w3.org/2009/XMLSchema/XMLSchema.xsd will change accordingly; the version at http://www.w3.org/2012/04/XMLSchema.xsd will not change. Previous dated (and unchanging) versions of this schema document include: http://www.w3.org/2012/01/XMLSchema.xsd (XSD 1.1 Proposed Recommendation) http://www.w3.org/2011/07/XMLSchema.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2009/04/XMLSchema.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2004/10/XMLSchema.xsd (XSD 1.0 Recommendation, Second Edition) http://www.w3.org/2001/05/XMLSchema.xsd (XSD 1.0 Recommendation, First Edition) </xs:documentation> </xs:annotation> <xs:simpleType name="derivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="substitution"/> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:group name="simpleDerivation"> <xs:choice> <xs:element ref="xs:restriction"/> <xs:element ref="xs:list"/> <xs:element ref="xs:union"/> </xs:choice> </xs:group> <xs:simpleType name="simpleDerivationSet"> <xs:annotation> <xs:documentation> #all or (possibly empty) subset of {restriction, extension, union, list} </xs:documentation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="list"/> <xs:enumeration value="union"/> <xs:enumeration value="restriction"/> <xs:enumeration value="extension"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="simpleType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleDerivation"/> <xs:attribute name="final" type="xs:simpleDerivationSet"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Can be restricted to required or forbidden </xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"> <xs:annotation> <xs:documentation> Required at the top level </xs:documentation> </xs:annotation> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" use="prohibited"> <xs:annotation> <xs:documentation> Forbidden when nested </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="final" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleType" type="xs:topLevelSimpleType" id="simpleType"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-simpleType"/> </xs:annotation> </xs:element> <xs:element name="facet" abstract="true"> <xs:annotation> <xs:documentation> An abstract element, representing facets in general. The facets defined by this spec are substitutable for this element, and implementation-defined facets should also name this as a substitution-group head. </xs:documentation> </xs:annotation> </xs:element> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:facet"/> <xs:any processContents="lax" namespace="##other"/> </xs:choice> </xs:sequence> </xs:group> <xs:element name="restriction" id="restriction"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-restriction"> base attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleRestrictionModel"/> <xs:attribute name="base" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="list" id="list"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-list"> itemType attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attribute name="itemType" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="union" id="union"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-union"> memberTypes attribute must be non-empty or there must be at least one simpleType child </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="memberTypes" use="optional"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="facet"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="value" use="required"/> <xs:attribute name="fixed" type="xs:boolean" default="false" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="noFixedFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="fixed" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="minExclusive" type="xs:facet" id="minExclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minExclusive"/> </xs:annotation> </xs:element> <xs:element name="minInclusive" type="xs:facet" id="minInclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minInclusive"/> </xs:annotation> </xs:element> <xs:element name="maxExclusive" type="xs:facet" id="maxExclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxExclusive"/> </xs:annotation> </xs:element> <xs:element name="maxInclusive" type="xs:facet" id="maxInclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxInclusive"/> </xs:annotation> </xs:element> <xs:complexType name="numFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:nonNegativeInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="intFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:integer" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="totalDigits" id="totalDigits" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-totalDigits"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:numFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:positiveInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="fractionDigits" type="xs:numFacet" id="fractionDigits" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-fractionDigits"/> </xs:annotation> </xs:element> <xs:element name="length" type="xs:numFacet" id="length" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-length"/> </xs:annotation> </xs:element> <xs:element name="minLength" type="xs:numFacet" id="minLength" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minLength"/> </xs:annotation> </xs:element> <xs:element name="maxLength" type="xs:numFacet" id="maxLength" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxLength"/> </xs:annotation> </xs:element> <xs:element name="enumeration" type="xs:noFixedFacet" id="enumeration" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-enumeration"/> </xs:annotation> </xs:element> <xs:element name="whiteSpace" id="whiteSpace" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-whiteSpace"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="preserve"/> <xs:enumeration value="replace"/> <xs:enumeration value="collapse"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="pattern" id="pattern" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-pattern"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:noFixedFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:string" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="assertion" type="xs:assertion" id="assertion" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-assertion"/> </xs:annotation> </xs:element> <xs:element name="explicitTimezone" id="explicitTimezone" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-explicitTimezone"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="optional"/> <xs:enumeration value="required"/> <xs:enumeration value="prohibited"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> In keeping with the XML Schema WG's standard versioning policy, this schema document will persist at the URI http://www.w3.org/2012/04/datatypes.xsd. At the date of issue it can also be found at the URI http://www.w3.org/2009/XMLSchema/datatypes.xsd. The schema document at that URI may however change in the future, in order to remain compatible with the latest version of XSD and its namespace. In other words, if XSD or the XML Schema namespace change, the version of this document at http://www.w3.org/2009/XMLSchema/datatypes.xsd will change accordingly; the version at http://www.w3.org/2012/04/datatypes.xsd will not change. Previous dated (and unchanging) versions of this schema document include: http://www.w3.org/2012/01/datatypes.xsd (XSD 1.1 Proposed Recommendation) http://www.w3.org/2011/07/datatypes.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2009/04/datatypes.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2004/10/datatypes.xsd (XSD 1.0 Recommendation, Second Edition) http://www.w3.org/2001/05/datatypes.xsd (XSD 1.0 Recommendation, First Edition) </xs:documentation> </xs:annotation> </xs:schema> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.1/datatypes.xsd��������������������������������������������0000664�0000000�0000000�00000042131�14211403446�0022711�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XSD 1.1//EN" "XMLSchema.dtd" [ <!-- Make sure that processors that do not read the external subset will know about the various IDs we declare --> <!ATTLIST xs:simpleType id ID #IMPLIED> <!ATTLIST xs:maxExclusive id ID #IMPLIED> <!ATTLIST xs:minExclusive id ID #IMPLIED> <!ATTLIST xs:maxInclusive id ID #IMPLIED> <!ATTLIST xs:minInclusive id ID #IMPLIED> <!ATTLIST xs:totalDigits id ID #IMPLIED> <!ATTLIST xs:fractionDigits id ID #IMPLIED> <!ATTLIST xs:length id ID #IMPLIED> <!ATTLIST xs:minLength id ID #IMPLIED> <!ATTLIST xs:maxLength id ID #IMPLIED> <!ATTLIST xs:enumeration id ID #IMPLIED> <!ATTLIST xs:pattern id ID #IMPLIED> <!ATTLIST xs:assertion id ID #IMPLIED> <!ATTLIST xs:explicitTimezone id ID #IMPLIED> <!ATTLIST xs:appinfo id ID #IMPLIED> <!ATTLIST xs:documentation id ID #IMPLIED> <!ATTLIST xs:list id ID #IMPLIED> <!ATTLIST xs:union id ID #IMPLIED> ]> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xml:lang="en" targetNamespace="http://www.w3.org/2001/XMLSchema" version="datatypes.xsd (rec-20120405)"> <xs:annotation> <xs:documentation source="../datatypes/datatypes.html"> The schema corresponding to this document is normative, with respect to the syntactic constraints it expresses in the XML Schema language. The documentation (within 'documentation' elements) below, is not normative, but rather highlights important aspects of the W3C Recommendation of which this is a part. See below (at the bottom of this document) for information about the revision and namespace-versioning policy governing this schema document. </xs:documentation> </xs:annotation> <xs:simpleType name="derivationControl"> <xs:annotation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="substitution"/> <xs:enumeration value="extension"/> <xs:enumeration value="restriction"/> <xs:enumeration value="list"/> <xs:enumeration value="union"/> </xs:restriction> </xs:simpleType> <xs:group name="simpleDerivation"> <xs:choice> <xs:element ref="xs:restriction"/> <xs:element ref="xs:list"/> <xs:element ref="xs:union"/> </xs:choice> </xs:group> <xs:simpleType name="simpleDerivationSet"> <xs:annotation> <xs:documentation> #all or (possibly empty) subset of {restriction, extension, union, list} </xs:documentation> <xs:documentation> A utility type, not for public use</xs:documentation> </xs:annotation> <xs:union> <xs:simpleType> <xs:restriction base="xs:token"> <xs:enumeration value="#all"/> </xs:restriction> </xs:simpleType> <xs:simpleType> <xs:list> <xs:simpleType> <xs:restriction base="xs:derivationControl"> <xs:enumeration value="list"/> <xs:enumeration value="union"/> <xs:enumeration value="restriction"/> <xs:enumeration value="extension"/> </xs:restriction> </xs:simpleType> </xs:list> </xs:simpleType> </xs:union> </xs:simpleType> <xs:complexType name="simpleType" abstract="true"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleDerivation"/> <xs:attribute name="final" type="xs:simpleDerivationSet"/> <xs:attribute name="name" type="xs:NCName"> <xs:annotation> <xs:documentation> Can be restricted to required or forbidden </xs:documentation> </xs:annotation> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="topLevelSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" type="xs:NCName" use="required"> <xs:annotation> <xs:documentation> Required at the top level </xs:documentation> </xs:annotation> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="localSimpleType"> <xs:complexContent> <xs:restriction base="xs:simpleType"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> <xs:group ref="xs:simpleDerivation"/> </xs:sequence> <xs:attribute name="name" use="prohibited"> <xs:annotation> <xs:documentation> Forbidden when nested </xs:documentation> </xs:annotation> </xs:attribute> <xs:attribute name="final" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="simpleType" type="xs:topLevelSimpleType" id="simpleType"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-simpleType"/> </xs:annotation> </xs:element> <xs:element name="facet" abstract="true"> <xs:annotation> <xs:documentation> An abstract element, representing facets in general. The facets defined by this spec are substitutable for this element, and implementation-defined facets should also name this as a substitution-group head. </xs:documentation> </xs:annotation> </xs:element> <xs:group name="simpleRestrictionModel"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="xs:facet"/> <xs:any processContents="lax" namespace="##other"/> </xs:choice> </xs:sequence> </xs:group> <xs:element name="restriction" id="restriction"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-restriction"> base attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:group ref="xs:simpleRestrictionModel"/> <xs:attribute name="base" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="list" id="list"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-list"> itemType attribute and simpleType child are mutually exclusive, but one or other is required </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/> </xs:sequence> <xs:attribute name="itemType" type="xs:QName" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="union" id="union"> <xs:complexType> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-union"> memberTypes attribute must be non-empty or there must be at least one simpleType child </xs:documentation> </xs:annotation> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="memberTypes" use="optional"> <xs:simpleType> <xs:list itemType="xs:QName"/> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:complexType name="facet"> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:attribute name="value" use="required"/> <xs:attribute name="fixed" type="xs:boolean" default="false" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="noFixedFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="fixed" use="prohibited"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="minExclusive" type="xs:facet" id="minExclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minExclusive"/> </xs:annotation> </xs:element> <xs:element name="minInclusive" type="xs:facet" id="minInclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minInclusive"/> </xs:annotation> </xs:element> <xs:element name="maxExclusive" type="xs:facet" id="maxExclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxExclusive"/> </xs:annotation> </xs:element> <xs:element name="maxInclusive" type="xs:facet" id="maxInclusive" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxInclusive"/> </xs:annotation> </xs:element> <xs:complexType name="numFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:nonNegativeInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:complexType name="intFacet"> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:integer" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> <xs:element name="totalDigits" id="totalDigits" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-totalDigits"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:numFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:positiveInteger" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="fractionDigits" type="xs:numFacet" id="fractionDigits" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-fractionDigits"/> </xs:annotation> </xs:element> <xs:element name="length" type="xs:numFacet" id="length" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-length"/> </xs:annotation> </xs:element> <xs:element name="minLength" type="xs:numFacet" id="minLength" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-minLength"/> </xs:annotation> </xs:element> <xs:element name="maxLength" type="xs:numFacet" id="maxLength" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-maxLength"/> </xs:annotation> </xs:element> <xs:element name="enumeration" type="xs:noFixedFacet" id="enumeration" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-enumeration"/> </xs:annotation> </xs:element> <xs:element name="whiteSpace" id="whiteSpace" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-whiteSpace"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="preserve"/> <xs:enumeration value="replace"/> <xs:enumeration value="collapse"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="pattern" id="pattern" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-pattern"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:noFixedFacet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" type="xs:string" use="required"/> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="assertion" type="xs:assertion" id="assertion" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-assertion"/> </xs:annotation> </xs:element> <xs:element name="explicitTimezone" id="explicitTimezone" substitutionGroup="xs:facet"> <xs:annotation> <xs:documentation source="http://www.w3.org/TR/xmlschema11-2/#element-explicitTimezone"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:facet"> <xs:sequence> <xs:element ref="xs:annotation" minOccurs="0"/> </xs:sequence> <xs:attribute name="value" use="required"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="optional"/> <xs:enumeration value="required"/> <xs:enumeration value="prohibited"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:anyAttribute namespace="##other" processContents="lax"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element> <xs:annotation> <xs:documentation> In keeping with the XML Schema WG's standard versioning policy, this schema document will persist at the URI http://www.w3.org/2012/04/datatypes.xsd. At the date of issue it can also be found at the URI http://www.w3.org/2009/XMLSchema/datatypes.xsd. The schema document at that URI may however change in the future, in order to remain compatible with the latest version of XSD and its namespace. In other words, if XSD or the XML Schema namespace change, the version of this document at http://www.w3.org/2009/XMLSchema/datatypes.xsd will change accordingly; the version at http://www.w3.org/2012/04/datatypes.xsd will not change. Previous dated (and unchanging) versions of this schema document include: http://www.w3.org/2012/01/datatypes.xsd (XSD 1.1 Proposed Recommendation) http://www.w3.org/2011/07/datatypes.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2009/04/datatypes.xsd (XSD 1.1 Candidate Recommendation) http://www.w3.org/2004/10/datatypes.xsd (XSD 1.0 Recommendation, Second Edition) http://www.w3.org/2001/05/datatypes.xsd (XSD 1.0 Recommendation, First Edition) </xs:documentation> </xs:annotation> </xs:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSD_1.1/xsd11-extra.xsd������������������������������������������0000664�0000000�0000000�00000007267�14211403446�0023007�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- Chameleon schema for defining XSD 1.1 list type builtins and to override openContent/defaultOpenContent declarations for the xmlschema library. --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:override schemaLocation="XMLSchema.xsd"> <xs:element name="openContent" id="openContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-openContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="any" minOccurs="0"> <!-- Add notQName attribute in xs:any particles --> <xs:complexType> <xs:complexContent> <xs:extension base="xs:wildcard"> <xs:attribute name="notQName" type="xs:qnameList" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="mode" default="interleave" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="none"/> <xs:enumeration value="interleave"/> <xs:enumeration value="suffix"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> <xs:element name="defaultOpenContent" id="defaultOpenContent"> <xs:annotation> <xs:documentation source="../structures/structures.html#element-defaultOpenContent"/> </xs:annotation> <xs:complexType> <xs:complexContent> <xs:extension base="xs:annotated"> <xs:sequence> <xs:element name="any"> <!-- Add notQName attribute in xs:any particles --> <xs:complexType> <xs:complexContent> <xs:extension base="xs:wildcard"> <xs:attribute name="notQName" type="xs:qnameList" use="optional"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:sequence> <xs:attribute name="appliesToEmpty" type="xs:boolean" default="false" use="optional"/> <xs:attribute name="mode" default="interleave" use="optional"> <xs:simpleType> <xs:restriction base="xs:NMTOKEN"> <xs:enumeration value="interleave"/> <xs:enumeration value="suffix"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:override> <xs:simpleType name="IDREFS" id="IDREFS"> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:IDREF"/> </xs:simpleType> <xs:minLength value="1" id="IDREFS.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="ENTITIES" id="ENTITIES"> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:ENTITY"/> </xs:simpleType> <xs:minLength value="1" id="ENTITIES.minLength"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="NMTOKENS" id="NMTOKENS"> <xs:restriction> <xs:simpleType> <xs:list itemType="xs:NMTOKEN"/> </xs:simpleType> <xs:minLength value="1" id="NMTOKENS.minLength"/> </xs:restriction> </xs:simpleType> </xs:schema> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSI/�������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017620�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/schemas/XSI/XMLSchema-instance_minimal.xsd�������������������������������0000664�0000000�0000000�00000000601�14211403446�0025426�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0'?> <xs:schema targetNamespace="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- A minimal schema that not requires the loading of xhtml namespace --> <xs:attribute name="nil"/> <xs:attribute name="type"/> <xs:attribute name="schemaLocation"/> <xs:attribute name="noNamespaceSchemaLocation"/> </xs:schema> �������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/�����������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017207�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/__init__.py������������������������������������������������������0000664�0000000�0000000�00000004075�14211403446�0021326�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """ Subpackage with unittest extensions for xmlschema. Includes common classes and helpers for building test scripts for xmlschema. The main part is a test factory for creating test cases from lists of paths to XSD or XML files. The list of cases can be defined within files named "testfiles". These are text files that contain a list of relative paths to XSD or XML files, that are used to dinamically build a set of test classes. Each path is followed by a list of options that defines a custom setting for each test. """ from urllib.request import urlopen from urllib.error import URLError from ._helpers import iter_nested_items, etree_elements_assert_equal from ._case_class import XsdValidatorTestCase from ._builders import make_schema_test_class, make_validation_test_class from ._factory import get_test_args, xsd_version_number, defuse_data, \ get_test_program_args_parser, get_test_line_args_parser, factory_tests from ._observers import SchemaObserver, ObservedXMLSchema10, ObservedXMLSchema11 def has_network_access(*locations): for url in locations: try: urlopen(url, timeout=5) except (URLError, OSError): pass else: return True return False SKIP_REMOTE_TESTS = not has_network_access( 'https://github.com/', 'https://www.w3.org/', 'https://www.sissa.it/' ) __all__ = [ 'XsdValidatorTestCase', 'make_schema_test_class', 'make_validation_test_class', 'get_test_args', 'xsd_version_number', 'defuse_data', 'get_test_program_args_parser', 'get_test_line_args_parser', 'factory_tests', 'SchemaObserver', 'ObservedXMLSchema10', 'ObservedXMLSchema11', 'has_network_access', 'iter_nested_items', 'etree_elements_assert_equal', 'SKIP_REMOTE_TESTS', ] �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/_builders.py�����������������������������������������������������0000664�0000000�0000000�00000072130�14211403446�0021534�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore import pdb import os import ast import pickle import time import logging import importlib import tempfile import warnings try: import lxml.etree as lxml_etree except ImportError: lxml_etree = None lxml_etree_element = None else: lxml_etree_element = lxml_etree.Element import xmlschema from xmlschema import XMLSchemaBase, XMLSchema11, XMLSchemaValidationError, \ XMLSchemaParseError, UnorderedConverter, ParkerConverter, BadgerFishConverter, \ AbderaConverter, JsonMLConverter, ColumnarConverter from xmlschema.names import XSD_IMPORT from xmlschema.helpers import local_name from xmlschema.etree import etree_tostring, ElementTree, \ py_etree_element from xmlschema.resources import fetch_namespaces from xmlschema.xpath import XMLSchemaContext from xmlschema.validators import XsdValidator, XsdType, Xsd11ComplexType from xmlschema.dataobjects import DataElementConverter, DataBindingConverter, DataElement try: from xmlschema.extras.codegen import PythonGenerator except ImportError: PythonGenerator = None from ._helpers import iter_nested_items, etree_elements_assert_equal from ._case_class import XsdValidatorTestCase from ._observers import SchemaObserver def make_schema_test_class(test_file, test_args, test_num, schema_class, check_with_lxml): """ Creates a schema test class. :param test_file: the schema test file path. :param test_args: line arguments for test case. :param test_num: a positive integer number associated with the test case. :param schema_class: the schema class to use. :param check_with_lxml: if `True` compare with lxml XMLSchema class, reporting anomalies. \ Works only for XSD 1.0 tests. """ xsd_file = os.path.relpath(test_file) # Extract schema test arguments expected_errors = test_args.errors expected_warnings = test_args.warnings inspect = test_args.inspect locations = test_args.locations defuse = test_args.defuse no_pickle = test_args.no_pickle debug_mode = test_args.debug codegen = test_args.codegen loglevel = logging.DEBUG if debug_mode else None class TestSchema(XsdValidatorTestCase): @classmethod def setUpClass(cls): cls.schema_class = schema_class cls.errors = [] cls.longMessage = True if debug_mode: print("\n##\n## Testing %r schema in debug mode.\n##" % xsd_file) pdb.set_trace() def check_xsd_file(self): if expected_errors > 0: schema = schema_class(xsd_file, validation='lax', locations=locations, defuse=defuse, loglevel=loglevel) else: schema = schema_class(xsd_file, locations=locations, defuse=defuse, loglevel=loglevel) self.errors.extend(schema.maps.all_errors) if inspect: components_ids = set([id(c) for c in schema.maps.iter_components()]) components_ids.update(id(c) for c in schema.meta_schema.iter_components()) missing = [ c for c in SchemaObserver.components if id(c) not in components_ids ] if missing: raise ValueError("schema missing %d components: %r" % (len(missing), missing)) # Pickling test (skip inspected schema classes test) if not inspect and not no_pickle: try: obj = pickle.dumps(schema) deserialized_schema = pickle.loads(obj) except pickle.PicklingError: # Don't raise if some schema parts (eg. a schema loaded from remote) # are built with the SafeXMLParser that uses pure Python elements. for e in schema.maps.iter_components(): elem = getattr(e, 'elem', getattr(e, 'root', None)) if isinstance(elem, py_etree_element): break else: raise else: self.assertTrue(isinstance(deserialized_schema, XMLSchemaBase), msg=xsd_file) self.assertEqual(schema.built, deserialized_schema.built, msg=xsd_file) # XPath API tests if not inspect and not self.errors: context = XMLSchemaContext(schema) elements = [x for x in schema.iter()] # Contains schema elements only xpath_context_elements = [x for x in context.iter() if isinstance(x, XsdValidator)] descendants = [x for x in context.iter_descendants('descendant-or-self')] self.assertTrue(x in descendants for x in xpath_context_elements) for e in elements: # Context elements can include elements of other schemas (by element ref) self.assertIn(e, xpath_context_elements, msg=xsd_file) # Checks on XSD types for xsd_type in schema.maps.iter_components(xsd_classes=XsdType): self.assertIn( xsd_type.content_type_label, {'empty', 'simple', 'element-only', 'mixed'}, msg=xsd_file ) # Check that the schema is valid also with XSD 1.1 validator if not expected_errors and schema_class.XSD_VERSION == '1.0': try: XMLSchema11(xsd_file, locations=locations, defuse=defuse, loglevel=loglevel) except XMLSchemaParseError as err: if not isinstance(err.validator, Xsd11ComplexType) or \ "is simple or has a simple content" not in str(err): raise # Not a case of forbidden complex content extension schema = schema_class(xsd_file, validation='lax', locations=locations, defuse=defuse, loglevel=loglevel) for error in schema.all_errors: if not isinstance(err.validator, Xsd11ComplexType) or \ "is simple or has a simple content" not in str(err): raise error # Check XML bindings module only for schemas that do not have errors if codegen and PythonGenerator is not None and not self.errors and \ all('schemaLocation' in e.attrib for e in schema.root if e.tag == XSD_IMPORT): generator = PythonGenerator(schema) with tempfile.TemporaryDirectory() as tempdir: cwd = os.getcwd() try: schema.export(tempdir, save_remote=True) os.chdir(tempdir) generator.render_to_files('bindings.py.jinja') spec = importlib.util.spec_from_file_location(tempdir, 'bindings.py') module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) finally: os.chdir(cwd) def check_xsd_file_with_lxml(self, xmlschema_time): start_time = time.time() lxs = lxml_etree.parse(xsd_file) try: lxml_etree.XMLSchema(lxs.getroot()) except lxml_etree.XMLSchemaParseError as err: if not self.errors: print("\nSchema error with lxml.etree.XMLSchema for file {!r} ({}): {}".format( xsd_file, self.__class__.__name__, str(err) )) else: if self.errors: msg = "\nUnrecognized errors with lxml.etree.XMLSchema for file {!r} ({}): {}" print(msg.format( xsd_file, self.__class__.__name__, '\n++++++\n'.join([str(e) for e in self.errors]) )) lxml_schema_time = time.time() - start_time if lxml_schema_time >= xmlschema_time: msg = "\nSlower lxml.etree.XMLSchema ({:.3f}s VS {:.3f}s) with file {!r} ({})" print(msg.format( lxml_schema_time, xmlschema_time, xsd_file, self.__class__.__name__ )) def test_xsd_file(self): if inspect: SchemaObserver.clear() del self.errors[:] start_time = time.time() if expected_warnings > 0: with warnings.catch_warnings(record=True) as include_import_warnings: warnings.simplefilter("always") self.check_xsd_file() self.assertEqual(len(include_import_warnings), expected_warnings, msg=xsd_file) else: self.check_xsd_file() # Check with lxml.etree.XMLSchema class if check_with_lxml and lxml_etree is not None: self.check_xsd_file_with_lxml(xmlschema_time=time.time() - start_time) self.check_errors(xsd_file, expected_errors) TestSchema.__name__ = TestSchema.__qualname__ = str('TestSchema{0:03}'.format(test_num)) return TestSchema def make_validation_test_class(test_file, test_args, test_num, schema_class, check_with_lxml): """ Creates a test class for checking xml instance validation. :param test_file: the XML test file path. :param test_args: line arguments for test case. :param test_num: a positive integer number associated with the test case. :param schema_class: the schema class to use. :param check_with_lxml: if `True` compare with lxml XMLSchema class, reporting anomalies. \ Works only for XSD 1.0 tests. """ xml_file = os.path.relpath(test_file) msg_tmpl = '%s: {0}:\n\n{1}' % xml_file # Extract schema test arguments expected_errors = test_args.errors expected_warnings = test_args.warnings inspect = test_args.inspect locations = test_args.locations defuse = test_args.defuse validation_only = test_args.validation_only no_pickle = test_args.no_pickle lax_encode = test_args.lax_encode debug_mode = test_args.debug codegen = test_args.codegen class TestValidator(XsdValidatorTestCase): @classmethod def setUpClass(cls): # Builds schema instance using 'lax' validation mode # to accepts also schemas with not crashing errors. cls.schema_class = schema_class source, _locations = xmlschema.fetch_schema_locations(xml_file, locations) cls.schema = schema_class(source, validation='lax', locations=_locations, defuse=defuse) if check_with_lxml and lxml_etree is not None: cls.lxml_schema = lxml_etree.parse(source) cls.errors = [] cls.chunks = [] cls.longMessage = True if debug_mode: print("\n##\n## Testing %r validation in debug mode.\n##" % xml_file) pdb.set_trace() def check_decode_encode(self, root, converter=None, **kwargs): namespaces = kwargs.get('namespaces', {}) lossy = converter in (ParkerConverter, AbderaConverter, ColumnarConverter) losslessly = converter is JsonMLConverter unordered = converter not in (AbderaConverter, JsonMLConverter) or \ kwargs.get('unordered', False) decoded_data1 = self.schema.decode(root, converter=converter, **kwargs) if isinstance(decoded_data1, tuple): decoded_data1 = decoded_data1[0] # When validation='lax' for _ in iter_nested_items(decoded_data1): pass try: elem1 = self.schema.encode( decoded_data1, path=root.tag, converter=converter, **kwargs ) except XMLSchemaValidationError as err: raise AssertionError(msg_tmpl.format("error during re-encoding", str(err))) if isinstance(elem1, tuple): # When validation='lax' if converter is not ParkerConverter and converter is not ColumnarConverter: for e in elem1[1]: self.check_namespace_prefixes(str(e)) elem1 = elem1[0] # Checks the encoded element to not contains reserved namespace prefixes if namespaces and all('ns%d' % k not in namespaces for k in range(10)): self.check_namespace_prefixes(etree_tostring(elem1, namespaces=namespaces)) # Main check: compare original a re-encoded tree try: etree_elements_assert_equal(root, elem1, strict=False, unordered=unordered) except AssertionError as err: # If the check fails retry only if the converter is lossy (eg. ParkerConverter) # or if the XML case has defaults taken from the schema or some part of data # decoding is skipped by schema wildcards (set the specific argument in testfiles). if lax_encode: # can't ensure encode equivalence on this case, # for example if the test case use defaults. pass elif lossy or unordered: # can't check encode equivalence if the converter # is lossy or if it is not fully ordered. pass elif losslessly: if debug_mode: pdb.set_trace() raise AssertionError( msg_tmpl.format("encoded tree differs from original", str(err)) ) else: # Lossy or augmenting cases are checked with another decoding/encoding pass decoded_data2 = self.schema.decode(elem1, converter=converter, **kwargs) if isinstance(decoded_data2, tuple): decoded_data2 = decoded_data2[0] try: self.assertEqual(decoded_data1, decoded_data2, msg=xml_file) except AssertionError: if debug_mode: pdb.set_trace() raise elem2 = self.schema.encode( decoded_data2, path=root.tag, converter=converter, **kwargs ) if isinstance(elem2, tuple): elem2 = elem2[0] try: etree_elements_assert_equal( elem1, elem2, strict=False, unordered=unordered ) except AssertionError as err: if debug_mode: pdb.set_trace() raise AssertionError( msg_tmpl.format("encoded tree differs after second pass", str(err)) ) def check_json_serialization(self, root, converter=None, **kwargs): lossy = converter in (ParkerConverter, AbderaConverter, ColumnarConverter) unordered = converter not in (AbderaConverter, JsonMLConverter) or \ kwargs.get('unordered', False) # Use str instead of float in order to preserve original data kwargs['decimal_type'] = str json_data1 = xmlschema.to_json(root, schema=self.schema, converter=converter, **kwargs) if isinstance(json_data1, tuple): json_data1 = json_data1[0] elem1 = xmlschema.from_json( json_data1, schema=self.schema, path=root.tag, converter=converter, **kwargs ) if isinstance(elem1, tuple): elem1 = elem1[0] if lax_encode: kwargs['validation'] = kwargs.get('validation', 'lax') json_data2 = xmlschema.to_json( elem1, schema=self.schema, converter=converter, **kwargs ) if isinstance(json_data2, tuple): json_data2 = json_data2[0] if json_data2 != json_data1 and (lax_encode or lossy or unordered): # Can't ensure decode equivalence if the test case use defaults, # white spaces are replaced/collapsed or the converter is lossy # or the decoding is unordered. return self.assertEqual(json_data2, json_data1, msg=xml_file) def check_decoding_with_element_tree(self): del self.errors[:] del self.chunks[:] def do_decoding(): for obj in self.schema.iter_decode(xml_file): if isinstance(obj, (xmlschema.XMLSchemaDecodeError, xmlschema.XMLSchemaValidationError)): self.errors.append(obj) else: self.chunks.append(obj) if expected_warnings == 0: do_decoding() else: with warnings.catch_warnings(record=True) as include_import_warnings: warnings.simplefilter("always") do_decoding() self.assertEqual(len(include_import_warnings), expected_warnings, msg=xml_file) self.check_errors(xml_file, expected_errors) if not self.chunks: raise ValueError("No decoded object returned!!") elif len(self.chunks) > 1: raise ValueError("Too many ({}) decoded objects returned: {}".format( len(self.chunks), self.chunks) ) elif not self.errors: try: skip_decoded_data = self.schema.decode(xml_file, validation='skip') self.assertEqual(skip_decoded_data, self.chunks[0], msg=xml_file) except AssertionError: if not lax_encode: raise def check_schema_serialization(self): # Repeat with serialized-deserialized schema (only for Python 3) serialized_schema = pickle.dumps(self.schema) deserialized_schema = pickle.loads(serialized_schema) deserialized_errors = [] deserialized_chunks = [] for obj in deserialized_schema.iter_decode(xml_file): if isinstance(obj, xmlschema.XMLSchemaValidationError): deserialized_errors.append(obj) else: deserialized_chunks.append(obj) self.assertEqual(len(deserialized_errors), len(self.errors), msg=xml_file) self.assertEqual(deserialized_chunks, self.chunks, msg=xml_file) def check_decode_api(self): # Compare with the decode API and other validation modes strict_decoded_data = self.schema.decode(xml_file) lax_decoded_data = self.schema.decode(xml_file, validation='lax') skip_decoded_data = self.schema.decode(xml_file, validation='skip') self.assertEqual(strict_decoded_data, self.chunks[0], msg=xml_file) self.assertEqual(lax_decoded_data[0], self.chunks[0], msg=xml_file) self.assertEqual(skip_decoded_data, self.chunks[0], msg=xml_file) def check_data_conversion_with_element_tree(self): root = ElementTree.parse(xml_file).getroot() namespaces = fetch_namespaces(xml_file) options = {'namespaces': namespaces} self.check_decode_encode(root, cdata_prefix='#', **options) # Default converter self.check_decode_encode(root, UnorderedConverter, cdata_prefix='#', **options) self.check_decode_encode(root, ParkerConverter, validation='lax', **options) self.check_decode_encode(root, ParkerConverter, validation='skip', **options) self.check_decode_encode(root, BadgerFishConverter, **options) self.check_decode_encode(root, AbderaConverter, **options) self.check_decode_encode(root, JsonMLConverter, **options) self.check_decode_encode(root, ColumnarConverter, validation='lax', **options) self.check_decode_encode(root, DataElementConverter, **options) self.check_decode_encode(root, DataBindingConverter, **options) self.schema.maps.clear_bindings() self.check_json_serialization(root, cdata_prefix='#', **options) self.check_json_serialization(root, UnorderedConverter, **options) self.check_json_serialization(root, ParkerConverter, validation='lax', **options) self.check_json_serialization(root, ParkerConverter, validation='skip', **options) self.check_json_serialization(root, BadgerFishConverter, **options) self.check_json_serialization(root, AbderaConverter, **options) self.check_json_serialization(root, JsonMLConverter, **options) self.check_json_serialization(root, ColumnarConverter, validation='lax', **options) self.check_decode_to_objects(root) self.check_decode_to_objects(root, with_bindings=True) self.schema.maps.clear_bindings() def check_decode_to_objects(self, root, with_bindings=False): data_element = self.schema.to_objects(xml_file, with_bindings) self.assertIsInstance(data_element, DataElement) self.assertEqual(data_element.tag, root.tag) if not with_bindings: self.assertIs(data_element.__class__, DataElement) else: self.assertEqual(data_element.tag, root.tag) self.assertTrue(data_element.__class__.__name__.endswith('Binding')) def check_data_conversion_with_lxml(self): xml_tree = lxml_etree.parse(xml_file) namespaces = fetch_namespaces(xml_file) lxml_errors = [] lxml_decoded_chunks = [] for obj in self.schema.iter_decode(xml_tree, namespaces=namespaces): if isinstance(obj, xmlschema.XMLSchemaValidationError): lxml_errors.append(obj) else: lxml_decoded_chunks.append(obj) self.assertEqual(lxml_decoded_chunks, self.chunks, msg=xml_file) self.assertEqual(len(lxml_errors), len(self.errors), msg=xml_file) if not lxml_errors: root = xml_tree.getroot() if namespaces.get(''): # Add a not empty prefix for encoding to avoid the use of reserved prefix ns0 namespaces['tns0'] = namespaces[''] options = { 'etree_element_class': lxml_etree_element, 'namespaces': namespaces, } self.check_decode_encode(root, cdata_prefix='#', **options) # Default converter self.check_decode_encode(root, ParkerConverter, validation='lax', **options) self.check_decode_encode(root, ParkerConverter, validation='skip', **options) self.check_decode_encode(root, BadgerFishConverter, **options) self.check_decode_encode(root, AbderaConverter, **options) self.check_decode_encode(root, JsonMLConverter, **options) self.check_decode_encode(root, UnorderedConverter, cdata_prefix='#', **options) self.check_json_serialization(root, cdata_prefix='#', **options) self.check_json_serialization(root, ParkerConverter, validation='lax', **options) self.check_json_serialization(root, ParkerConverter, validation='skip', **options) self.check_json_serialization(root, BadgerFishConverter, **options) self.check_json_serialization(root, AbderaConverter, **options) self.check_json_serialization(root, JsonMLConverter, **options) self.check_json_serialization(root, UnorderedConverter, **options) def check_validate_and_is_valid_api(self): if expected_errors: self.assertFalse(self.schema.is_valid(xml_file), msg=xml_file) with self.assertRaises(XMLSchemaValidationError, msg=xml_file): self.schema.validate(xml_file) else: self.assertTrue(self.schema.is_valid(xml_file), msg=xml_file) self.assertIsNone(self.schema.validate(xml_file), msg=xml_file) def check_iter_errors(self): errors = list(self.schema.iter_errors(xml_file)) for e in errors: self.assertIsInstance(e.reason, str, msg=xml_file) self.assertEqual(len(errors), expected_errors, msg=xml_file) module_api_errors = list(xmlschema.iter_errors(xml_file, schema=self.schema)) self.assertEqual(len(errors), len(module_api_errors), msg=xml_file) for e, api_error in zip(errors, module_api_errors): self.assertEqual(e.reason, api_error.reason, msg=xml_file) lazy_errors = list(xmlschema.iter_errors(xml_file, schema=self.schema, lazy=True)) self.assertEqual(len(errors), len(lazy_errors), msg=xml_file) for e, lazy_error in zip(errors, lazy_errors): self.assertEqual(e.reason, lazy_error.reason, msg=xml_file) # TODO: Test also lazy validation with lazy=2. # This needs two fixes in XPath: # 1) find has to retrieve also element substitutes # 2) multiple XSD type match on tokens that have wildcard parent (eg. /root/*/name) def check_lxml_validation(self): try: schema = lxml_etree.XMLSchema(self.lxml_schema.getroot()) except lxml_etree.XMLSchemaParseError: print("\nSkip lxml.etree.XMLSchema validation test for {!r} ({})". format(xml_file, TestValidator.__name__, )) else: xml_tree = lxml_etree.parse(xml_file) if self.errors: self.assertFalse(schema.validate(xml_tree), msg=xml_file) else: self.assertTrue(schema.validate(xml_tree), msg=xml_file) def check_validation_with_generated_code(self): generator = PythonGenerator(self.schema) python_module = generator.render('bindings.py.jinja')[0] ast_module = ast.parse(python_module) self.assertIsInstance(ast_module, ast.Module) with tempfile.TemporaryDirectory() as tempdir: module_name = '{}.py'.format(self.schema.name.rstrip('.xsd')) cwd = os.getcwd() try: self.schema.export(tempdir, save_remote=True) os.chdir(tempdir) with open(module_name, 'w') as fp: fp.write(python_module) spec = importlib.util.spec_from_file_location(tempdir, module_name) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) xml_root = ElementTree.parse(os.path.join(cwd, xml_file)).getroot() bindings = [x for x in filter(lambda x: x.endswith('Binding'), dir(module))] if len(bindings) == 1: class_name = bindings[0] else: class_name = '{}Binding'.format( local_name(xml_root.tag).title().replace('_', '')) binding_class = getattr(module, class_name) xml_data = binding_class.fromsource(os.path.join(cwd, xml_file)) self.assertEqual(xml_data.tag, xml_root.tag) finally: os.chdir(cwd) def test_xml_document_validation(self): if not validation_only: self.check_decoding_with_element_tree() if not inspect and not no_pickle: self.check_schema_serialization() if not self.errors: self.check_data_conversion_with_element_tree() if lxml_etree is not None: self.check_data_conversion_with_lxml() self.check_iter_errors() self.check_validate_and_is_valid_api() if check_with_lxml and lxml_etree is not None: self.check_lxml_validation() # Test validation with XML data bindings only for instances and # schemas that do not have errors and imports without locations if not validation_only and codegen and PythonGenerator is not None and \ not self.errors and not self.schema.all_errors and \ all('schemaLocation' in e.attrib for e in self.schema.root if e.tag == XSD_IMPORT): self.check_validation_with_generated_code() TestValidator.__name__ = TestValidator.__qualname__ = 'TestValidator{0:03}'.format(test_num) return TestValidator ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/_case_class.py���������������������������������������������������0000664�0000000�0000000�00000017226�14211403446�0022030�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """ Tests subpackage module: common definitions for unittest scripts of the 'xmlschema' package. """ import unittest import re import os from textwrap import dedent from xmlschema.exceptions import XMLSchemaValueError from xmlschema.names import XSD_NAMESPACE, XSI_NAMESPACE, XSD_SCHEMA from xmlschema.helpers import get_namespace from xmlschema.etree import is_etree_element, etree_element from xmlschema.resources import fetch_namespaces from xmlschema.validators import XMLSchema10 from ._helpers import etree_elements_assert_equal PROTECTED_PREFIX_PATTERN = re.compile(r'\bns\d:') SCHEMA_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="{0}"> {1} </xs:schema>""" class XsdValidatorTestCase(unittest.TestCase): """ Base class for testing XSD validators. """ TEST_CASES_DIR = None schema_class = XMLSchema10 @classmethod def setUpClass(cls): cls.errors = [] cls.xsd_types = cls.schema_class.builtin_types() cls.content_pattern = re.compile(r'(<|<xs:)(sequence|choice|all)') cls.default_namespaces = { 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'tns': 'http://xmlschema.test/ns', 'ns': 'ns', } if os.path.isfile(cls.casepath('testfiles')): cls.vh_dir = cls.casepath('examples/vehicles') cls.vh_xsd_file = cls.casepath('examples/vehicles/vehicles.xsd') cls.vh_xml_file = cls.casepath('examples/vehicles/vehicles.xml') cls.vh_json_file = cls.casepath('examples/vehicles/vehicles.json') cls.vh_schema = cls.schema_class(cls.vh_xsd_file) cls.vh_namespaces = fetch_namespaces(cls.vh_xml_file) cls.col_dir = cls.casepath('examples/collection') cls.col_xsd_file = cls.casepath('examples/collection/collection.xsd') cls.col_xml_file = cls.casepath('examples/collection/collection.xml') cls.col_json_file = cls.casepath('examples/collection/collection.json') cls.col_schema = cls.schema_class(cls.col_xsd_file) cls.col_namespaces = fetch_namespaces(cls.col_xml_file) cls.st_xsd_file = cls.casepath('features/decoder/simple-types.xsd') cls.st_schema = cls.schema_class(cls.st_xsd_file) cls.models_xsd_file = cls.casepath('features/models/models.xsd') cls.models_schema = cls.schema_class(cls.models_xsd_file) @classmethod def casepath(cls, relative_path): """ Returns the absolute path from a relative path specified from the referenced TEST_CASES_DIR. """ return os.path.join(cls.TEST_CASES_DIR or '', relative_path) def get_schema_source(self, source): """ Returns a schema source that can be used to create an XMLSchema instance. :param source: A string or an ElementTree's Element. :return: An schema source string, an ElementTree's Element or a full pathname. """ if is_etree_element(source): if source.tag in (XSD_SCHEMA, 'schema'): return source elif get_namespace(source.tag): raise XMLSchemaValueError("source %r namespace has to be empty." % source) elif source.tag not in {'element', 'attribute', 'simpleType', 'complexType', 'group', 'attributeGroup', 'notation'}: raise XMLSchemaValueError("% is not an XSD global definition/declaration." % source) root = etree_element('schema', attrib={ 'xmlns:xs': XSD_NAMESPACE, 'xmlns:xsi': XSI_NAMESPACE, 'elementFormDefault': "qualified", 'version': self.schema_class.XSD_VERSION, }) root.append(source) return root else: source = dedent(source.strip()) if not source.startswith('<'): return self.casepath(source) elif source.startswith('<?xml ') or source.startswith('<xs:schema '): return source else: return SCHEMA_TEMPLATE.format(self.schema_class.XSD_VERSION, source) def get_schema(self, source, **kwargs): return self.schema_class(self.get_schema_source(source), **kwargs) def get_element(self, name, **attrib): source = '<xs:element name="{}" {}/>'.format( name, ' '.join('%s="%s"' % (k, v) for k, v in attrib.items()) ) schema = self.schema_class(self.get_schema_source(source)) return schema.elements[name] def check_etree_elements(self, elem, other): """Checks if two ElementTree elements are equal.""" try: self.assertIsNone( etree_elements_assert_equal(elem, other, strict=False, skip_comments=True) ) except AssertionError as err: self.assertIsNone(err, None) def check_namespace_prefixes(self, s): """Checks that a string doesn't contain protected prefixes (ns0, ns1 ...).""" match = PROTECTED_PREFIX_PATTERN.search(s) if match: msg = "Protected prefix {!r} found:\n {}".format(match.group(0), s) self.assertIsNone(match, msg) def check_schema(self, source, expected=None, **kwargs): """ Create a schema for a test case. :param source: A relative path or a root Element or a portion of schema for a template. :param expected: If it's an Exception class test the schema for raise an error. \ Otherwise build the schema and test a condition if expected is a callable, or make \ a substring test if it's not `None` (maybe a string). Then returns the schema instance. """ if isinstance(expected, type) and issubclass(expected, Exception): with self.assertRaises(expected): self.schema_class(self.get_schema_source(source), **kwargs) else: schema = self.schema_class(self.get_schema_source(source), **kwargs) if callable(expected): self.assertTrue(expected(schema)) return schema def check_errors(self, path, expected): """ Checks schema or validation errors, checking information completeness of the instances and those number against expected. :param path: the path of the test case. :param expected: the number of expected errors. """ for e in self.errors: error_string = str(e) self.assertTrue(e.path, "Missing path for: %s" % error_string) if e.namespaces: self.check_namespace_prefixes(error_string) if not self.errors and expected: raise ValueError("{!r}: found no errors when {} expected.".format(path, expected)) elif len(self.errors) != expected: num_errors = len(self.errors) if num_errors == 1: msg = "{!r}: n.{} errors expected, found {}:\n\n{}" elif num_errors <= 5: msg = "{!r}: n.{} errors expected, found {}. Errors follow:\n\n{}" else: msg = "{!r}: n.{} errors expected, found {}. First five errors follow:\n\n{}" error_string = '\n++++++++++\n\n'.join([str(e) for e in self.errors[:5]]) raise ValueError(msg.format(path, expected, len(self.errors), error_string)) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/_factory.py������������������������������������������������������0000664�0000000�0000000�00000022334�14211403446�0021373�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """ Test factory for creating test cases from lists of paths to XSD or XML files. The list of cases can be defined within files named "testfiles". These are text files that contain a list of relative paths to XSD or XML files, that are used to dinamically build a set of test classes. Each path is followed by a list of options that defines a custom setting for each test. """ import re import argparse import os import fileinput import logging from xmlschema.cli import xsd_version_number, defuse_data from xmlschema.validators import XMLSchema10, XMLSchema11 from ._observers import ObservedXMLSchema10, ObservedXMLSchema11 logger = logging.getLogger(__file__) def get_test_args(args_line): """Returns the list of arguments from provided text line.""" try: args_line, _ = args_line.split('#', 1) # Strip optional ending comment except ValueError: pass return re.split(r'(?<!\\) ', args_line.strip()) def get_test_program_args_parser(default_testfiles): """ Gets an argument parser for building test scripts for schemas and xml files. The returned parser has many arguments of unittest's TestProgram plus some arguments for selecting testfiles and XML schema options. """ parser = argparse.ArgumentParser(add_help=True) # unittest's arguments parser.add_argument('-v', '--verbose', dest='verbosity', default=1, action='store_const', const=2, help='Verbose output') parser.add_argument('-q', '--quiet', dest='verbosity', action='store_const', const=0, help='Quiet output') parser.add_argument('--locals', dest='tb_locals', action='store_true', help='Show local variables in tracebacks') parser.add_argument('-f', '--failfast', dest='failfast', action='store_true', help='Stop on first fail or error') parser.add_argument('-c', '--catch', dest='catchbreak', action='store_true', help='Catch Ctrl-C and display results so far') parser.add_argument('-b', '--buffer', dest='buffer', action='store_true', help='Buffer stdout and stderr during tests') parser.add_argument('-k', dest='patterns', action='append', default=list(), help='Only run tests which match the given substring') # xmlschema's arguments parser.add_argument('--lxml', dest='lxml', action='store_true', default=False, help='Check also with lxml.etree.XMLSchema (for XSD 1.0)') parser.add_argument('--codegen', action="store_true", default=False, help="Test code generation with XML data bindings module.") parser.add_argument('testfiles', type=str, nargs='*', default=default_testfiles, help="Test cases directory.") return parser def get_test_line_args_parser(): """Gets an arguments parser for uncommented on not blank "testfiles" lines.""" parser = argparse.ArgumentParser(add_help=True) parser.usage = "TEST_FILE [OPTIONS]\nTry 'TEST_FILE --help' for more information." parser.add_argument('filename', metavar='TEST_FILE', type=str, help="Test filename (relative path).") parser.add_argument( '-L', dest='locations', nargs=2, type=str, default=None, action='append', metavar="URI-URL", help="Schema location hint overrides." ) parser.add_argument( '--version', dest='version', metavar='VERSION', type=xsd_version_number, default='1.0', help="XSD schema version to use for the test case (default is 1.0)." ) parser.add_argument( '--errors', type=int, default=0, metavar='NUM', help="Number of errors expected (default=0)." ) parser.add_argument( '--warnings', type=int, default=0, metavar='NUM', help="Number of warnings expected (default=0)." ) parser.add_argument( '--inspect', action="store_true", default=False, help="Inspect using an observed custom schema class." ) parser.add_argument( '--defuse', metavar='(always, remote, never)', type=defuse_data, default='remote', help="Define when to use the defused XML data loaders." ) parser.add_argument( '--timeout', type=int, default=300, metavar='SEC', help="Timeout for fetching resources (default=300)." ) parser.add_argument( '--validation-only', action="store_true", default=False, help="Skip decode/encode tests on XML data." ) parser.add_argument( '--no-pickle', action="store_true", default=False, help="Skip pickling/unpickling test on schema (max recursion exceeded)." ) parser.add_argument( '--lax-encode', action="store_true", default=False, help="Use lax mode on encode checks (for cases where test data uses default or " "fixed values or some test data are skipped by wildcards processContents). " "Ignored on schema tests." ) parser.add_argument( '--debug', action="store_true", default=False, help="Activate the debug mode (only the cases with --debug are executed).", ) parser.add_argument( '--codegen', action="store_true", default=False, help="Test code generation with XML data bindings module. For default " "test code generation if the same command option is provided.", ) return parser def factory_tests(test_class_builder, testfiles, suffix, check_with_lxml=False, codegen=False, verbosity=1): """ Factory function for file based schema/validation cases. :param test_class_builder: the test class builder function. :param testfiles: a single or a list of testfiles indexes. :param suffix: the suffix ('xml' or 'xsd') to consider for cases. :param check_with_lxml: if `True` compare with lxml XMLSchema class, \ reporting anomalies. Works only for XSD 1.0 tests. :param codegen: if `True` is provided checks code generation with XML data \ bindings module for all tests. For default is `False` and code generation \ is tested only for the cases where the same option is provided. :param verbosity: the unittest's verbosity, can be 0, 1 or 2. :return: a list of test classes. """ test_classes = {} test_num = 0 debug_mode = False line_buffer = [] test_line_parser = get_test_line_args_parser() for line in fileinput.input(testfiles): line = line.strip() if not line or line[0] == '#': if not line_buffer: continue else: raise SyntaxError("Empty continuation at line %d!" % fileinput.filelineno()) elif '#' in line: line = line.split('#', 1)[0].rstrip() # Process line continuations if line[-1] == '\\': line_buffer.append(line[:-1].strip()) continue elif line_buffer: line_buffer.append(line) line = ' '.join(line_buffer) del line_buffer[:] test_args = test_line_parser.parse_args(get_test_args(line)) if test_args.locations is not None: test_args.locations = {k.strip('\'"'): v for k, v in test_args.locations} if codegen: test_args.codegen = True test_file = os.path.join(os.path.dirname(fileinput.filename()), test_args.filename) if os.path.isdir(test_file): logger.debug("Skip %s: is a directory.", test_file) continue elif os.path.splitext(test_file)[1].lower() != '.%s' % suffix: logger.debug("Skip %s: wrong suffix.", test_file) continue elif not os.path.isfile(test_file): logger.error("Skip %s: is not a file.", test_file) continue test_num += 1 # Debug mode activation if debug_mode: if not test_args.debug: continue elif test_args.debug: debug_mode = True msg = "Debug mode activated: discard previous %r test classes." logger.debug(msg, len(test_classes)) test_classes.clear() if test_args.version == '1.0': schema_class = ObservedXMLSchema10 if test_args.inspect else XMLSchema10 test_class = test_class_builder( test_file, test_args, test_num, schema_class, check_with_lxml ) else: schema_class = ObservedXMLSchema11 if test_args.inspect else XMLSchema11 test_class = test_class_builder( test_file, test_args, test_num, schema_class, check_with_lxml=False ) test_classes[test_class.__name__] = test_class if verbosity == 2: print(f"Create case {test_class.__name__} for file {os.path.relpath(test_file)}") logger.debug("Add XSD %s test class %r.", test_args.version, test_class.__name__) if line_buffer: raise ValueError("Not completed line continuation at the end!") return test_classes ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/_helpers.py������������������������������������������������������0000664�0000000�0000000�00000015523�14211403446�0021370�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import re from typing import Any, Dict, List, Type, Union, Iterator from ..helpers import get_namespace, get_qname from ..etree import etree_element _REGEX_SPACES = re.compile(r'\s+') def iter_nested_items(items: Union[Dict[Any, Any], List[Any]], dict_class: Type[Dict[Any, Any]] = dict, list_class: Type[List[Any]] = list) -> Iterator[Any]: """Iterates a nested object composed by lists and dictionaries.""" if isinstance(items, dict_class): for k, v in items.items(): yield from iter_nested_items(v, dict_class, list_class) elif isinstance(items, list_class): for item in items: yield from iter_nested_items(item, dict_class, list_class) elif isinstance(items, dict): raise TypeError("%r: is a dict() instead of %r." % (items, dict_class)) elif isinstance(items, list): raise TypeError("%r: is a list() instead of %r." % (items, list_class)) else: yield items def etree_elements_assert_equal(elem: etree_element, other: etree_element, strict: bool = True, skip_comments: bool = True, unordered: bool = False) -> None: """ Tests the equality of two XML Element trees. :param elem: the master Element tree, reference for namespace mapping. :param other: the other Element tree that has to be compared. :param strict: asserts strictly equality. `True` for default. :param skip_comments: skip comments from comparison. :param unordered: children may have different order. :raise: an AssertionError containing information about first difference encountered. """ children: Union[etree_element, List[etree_element]] if unordered: children = sorted(elem, key=lambda x: '' if callable(x.tag) else x.tag) other_children = iter(sorted( other, key=lambda x: '' if callable(x.tag) else x.tag )) else: children = elem other_children = iter(other) namespace = '' for e1 in children: if skip_comments and callable(e1.tag): continue try: while True: e2 = next(other_children) if not skip_comments or not callable(e2.tag): break except StopIteration: raise AssertionError("Node %r has more children than %r" % (elem, other)) if strict or e1 is elem: if e1.tag != e2.tag: raise AssertionError("%r != %r: tags differ" % (e1, e2)) else: namespace = get_namespace(e1.tag) or namespace if get_qname(namespace, e1.tag) != get_qname(namespace, e2.tag): raise AssertionError("%r != %r: tags differ." % (e1, e2)) # Attributes if e1.attrib != e2.attrib: if strict: msg = "{!r} != {!r}: attributes differ: {!r} != {!r}" raise AssertionError(msg.format(e1, e2, e1.attrib, e2.attrib)) else: msg = "%r != %r: attribute keys differ: %r != %r" if sorted(e1.attrib.keys()) != sorted(e2.attrib.keys()): raise AssertionError(msg % (e1, e2, e1.attrib.keys(), e2.attrib.keys())) for k in e1.attrib: a1, a2 = e1.attrib[k].strip(), e2.attrib[k].strip() if a1 != a2: try: if float(a1) != float(a2): raise ValueError() except (ValueError, TypeError): msg = "%r != %r: attribute %r values differ: %r != %r" raise AssertionError(msg % (e1, e2, k, a1, a2)) from None # Number of children if skip_comments: nc1 = len([c for c in e1 if not callable(c.tag)]) nc2 = len([c for c in e2 if not callable(c.tag)]) else: nc1 = len(e1) nc2 = len(e2) if nc1 != nc2: msg = "%r != %r: children number differ: %r != %r" raise AssertionError(msg % (e1, e2, nc1, nc2)) # Text if e1.text != e2.text: message = "%r != %r: texts differ: %r != %r" % (e1, e2, e1.text, e2.text) if strict: raise AssertionError(message) elif e1.text is None: if e2.text is not None and e2.text.strip(): raise AssertionError(message) elif e2.text is None: if e1.text.strip(): raise AssertionError(message) elif _REGEX_SPACES.sub('', e1.text.strip()) != _REGEX_SPACES.sub('', e2.text.strip()): text1 = e1.text.strip() text2 = e2.text.strip() if text1 == 'false': if text2 != '0': raise AssertionError(message) elif text1 == 'true': if text2 != '1': raise AssertionError(message) elif text2 == 'false': if text1 != '0': raise AssertionError(message) elif text2 == 'true': if text1 != '1': raise AssertionError(message) else: try: items1 = text1.split() items2 = text2.split() if len(items1) != len(items2): raise ValueError() if not all(float(x1) == float(x2) for x1, x2 in zip(items1, items2)): raise ValueError() except (AssertionError, ValueError, TypeError): raise AssertionError(message) from None # Tail if e1.tail != e2.tail: message = "%r != %r: tails differ: %r != %r" % (e1, e2, e1.tail, e2.tail) if strict: raise AssertionError(message) elif e1.tail is None: if e2.tail is not None and e2.tail.strip(): raise AssertionError(message) elif e2.tail is None: if e1.tail.strip(): raise AssertionError(message) elif e1.tail.strip() != e2.tail.strip(): raise AssertionError(message) etree_elements_assert_equal(e1, e2, strict, skip_comments, unordered) try: next(other_children) except StopIteration: pass else: raise AssertionError("Node %r has lesser children than %r." % (elem, other)) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/testing/_observers.py����������������������������������������������������0000664�0000000�0000000�00000011424�14211403446�0021734�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # # type: ignore """ Observers for testing XMLSchema classes. """ from functools import wraps from ..names import XSD_NAMESPACE, XSD_ANY_TYPE from ..validators import XMLSchema10, XMLSchema11, XsdGroup, \ XsdAttributeGroup, XsdComplexType, XsdComponent class SchemaObserver: """ Observer that registers created components. Run the 'clear' method after each usage. """ components = [] dummy_components = [] @classmethod def observed_builder(cls, builder): if isinstance(builder, type): class BuilderProxy(builder): def __init__(self, *args, **kwargs): super(BuilderProxy, self).__init__(*args, **kwargs) assert isinstance(self, XsdComponent) if not cls.is_dummy_component(self): cls.components.append(self) else: cls.dummy_components.append(self) BuilderProxy.__name__ = builder.__name__ return BuilderProxy elif callable(builder): @wraps(builder) def builder_proxy(*args, **kwargs): obj = builder(*args, **kwargs) assert isinstance(obj, XsdComponent) if not cls.is_dummy_component(obj): cls.components.append(obj) else: cls.dummy_components.append(obj) return obj return builder_proxy @classmethod def clear(cls) -> None: del cls.components[:] del cls.dummy_components[:] @classmethod def is_dummy_component(cls, component) -> bool: # Dummy components are empty attribute groups and xs:anyType # definitions not related to XSD namespace. if component.parent in cls.dummy_components: return True elif isinstance(component, XsdAttributeGroup): return not component elif isinstance(component, XsdComplexType): return component.name == XSD_ANY_TYPE and \ component.target_namespace != XSD_NAMESPACE elif isinstance(component, XsdGroup) and component.parent is not None: return component.parent.name == XSD_ANY_TYPE and \ component.target_namespace != XSD_NAMESPACE return False observed_builder = SchemaObserver.observed_builder class ObservedXMLSchema10(XMLSchema10): xsd_notation_class = observed_builder(XMLSchema10.xsd_notation_class) xsd_complex_type_class = observed_builder(XMLSchema10.xsd_complex_type_class) xsd_attribute_class = observed_builder(XMLSchema10.xsd_attribute_class) xsd_any_attribute_class = observed_builder(XMLSchema10.xsd_any_attribute_class) xsd_attribute_group_class = observed_builder(XMLSchema10.xsd_attribute_group_class) xsd_group_class = observed_builder(XMLSchema10.xsd_group_class) xsd_element_class = observed_builder(XMLSchema10.xsd_element_class) xsd_any_class = observed_builder(XMLSchema10.xsd_any_class) xsd_atomic_restriction_class = observed_builder(XMLSchema10.xsd_atomic_restriction_class) xsd_list_class = observed_builder(XMLSchema10.xsd_list_class) xsd_union_class = observed_builder(XMLSchema10.xsd_union_class) xsd_key_class = observed_builder(XMLSchema10.xsd_key_class) xsd_keyref_class = observed_builder(XMLSchema10.xsd_keyref_class) xsd_unique_class = observed_builder(XMLSchema10.xsd_unique_class) class ObservedXMLSchema11(XMLSchema11): xsd_notation_class = observed_builder(XMLSchema11.xsd_notation_class) xsd_complex_type_class = observed_builder(XMLSchema11.xsd_complex_type_class) xsd_attribute_class = observed_builder(XMLSchema11.xsd_attribute_class) xsd_any_attribute_class = observed_builder(XMLSchema11.xsd_any_attribute_class) xsd_attribute_group_class = observed_builder(XMLSchema11.xsd_attribute_group_class) xsd_group_class = observed_builder(XMLSchema11.xsd_group_class) xsd_element_class = observed_builder(XMLSchema11.xsd_element_class) xsd_any_class = observed_builder(XMLSchema11.xsd_any_class) xsd_atomic_restriction_class = observed_builder(XMLSchema11.xsd_atomic_restriction_class) xsd_list_class = observed_builder(XMLSchema11.xsd_list_class) xsd_union_class = observed_builder(XMLSchema11.xsd_union_class) xsd_key_class = observed_builder(XMLSchema11.xsd_key_class) xsd_keyref_class = observed_builder(XMLSchema11.xsd_keyref_class) xsd_unique_class = observed_builder(XMLSchema11.xsd_unique_class) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/��������������������������������������������������������������0000775�0000000�0000000�00000000000�14211403446�0017702�5����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/__init__.py���������������������������������������������������0000664�0000000�0000000�00000006745�14211403446�0022027�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from .exceptions import XMLSchemaValidatorError, XMLSchemaParseError, \ XMLSchemaModelError, XMLSchemaModelDepthError, XMLSchemaValidationError, \ XMLSchemaDecodeError, XMLSchemaEncodeError, XMLSchemaNotBuiltError, \ XMLSchemaChildrenValidationError, XMLSchemaIncludeWarning, \ XMLSchemaImportWarning, XMLSchemaTypeTableWarning from .xsdbase import XsdValidator, XsdComponent, XsdAnnotation, XsdType, \ ValidationMixin from .particles import ParticleMixin from .assertions import XsdAssert from .notations import XsdNotation from .identities import XsdSelector, XsdFieldSelector, XsdIdentity, XsdKeyref, XsdKey, \ XsdUnique, Xsd11Keyref, Xsd11Key, Xsd11Unique from .facets import XsdFacet, XsdWhiteSpaceFacet, XsdLengthFacet, XsdMinLengthFacet, \ XsdMaxLengthFacet, XsdMinExclusiveFacet, XsdMinInclusiveFacet, XsdMaxExclusiveFacet, \ XsdMaxInclusiveFacet, XsdFractionDigitsFacet, XsdTotalDigitsFacet, \ XsdExplicitTimezoneFacet, XsdPatternFacets, XsdEnumerationFacets, XsdAssertionFacet from .wildcards import XsdAnyElement, Xsd11AnyElement, XsdAnyAttribute, Xsd11AnyAttribute, \ XsdOpenContent, XsdDefaultOpenContent from .attributes import XsdAttribute, Xsd11Attribute, XsdAttributeGroup from .simple_types import XsdSimpleType, XsdAtomic, XsdAtomicBuiltin, \ XsdAtomicRestriction, Xsd11AtomicRestriction, XsdList, XsdUnion, Xsd11Union from .complex_types import XsdComplexType, Xsd11ComplexType from .models import ModelVisitor from .groups import XsdGroup, Xsd11Group from .elements import XsdElement, Xsd11Element, XsdAlternative from .global_maps import XsdGlobals from .schemas import XMLSchemaMeta, XMLSchemaBase, XMLSchema, XMLSchema10, XMLSchema11 __all__ = [ 'XMLSchemaValidatorError', 'XMLSchemaParseError', 'XMLSchemaModelError', 'XMLSchemaModelDepthError', 'XMLSchemaValidationError', 'XMLSchemaDecodeError', 'XMLSchemaEncodeError', 'XMLSchemaNotBuiltError', 'XMLSchemaChildrenValidationError', 'XMLSchemaIncludeWarning', 'XMLSchemaImportWarning', 'XMLSchemaTypeTableWarning', 'XsdValidator', 'XsdComponent', 'XsdAnnotation', 'XsdType', 'ValidationMixin', 'ParticleMixin', 'XsdAssert', 'XsdNotation', 'XsdSelector', 'XsdFieldSelector', 'XsdIdentity', 'XsdKeyref', 'XsdKey', 'XsdUnique', 'Xsd11Keyref', 'Xsd11Key', 'Xsd11Unique', 'XsdFacet', 'XsdWhiteSpaceFacet', 'XsdLengthFacet', 'XsdMinLengthFacet', 'XsdMaxLengthFacet', 'XsdMinExclusiveFacet', 'XsdMinInclusiveFacet', 'XsdMaxExclusiveFacet', 'XsdMaxInclusiveFacet', 'XsdFractionDigitsFacet', 'XsdTotalDigitsFacet', 'XsdExplicitTimezoneFacet', 'XsdPatternFacets', 'XsdEnumerationFacets', 'XsdAssertionFacet', 'XsdAnyElement', 'Xsd11AnyElement', 'XsdAnyAttribute', 'Xsd11AnyAttribute', 'XsdOpenContent', 'XsdDefaultOpenContent', 'XsdAttribute', 'Xsd11Attribute', 'XsdAttributeGroup', 'XsdSimpleType', 'XsdAtomic', 'XsdAtomicBuiltin', 'XsdAtomicRestriction', 'Xsd11AtomicRestriction', 'XsdList', 'XsdUnion', 'Xsd11Union', 'XsdComplexType', 'Xsd11ComplexType', 'ModelVisitor', 'XsdGroup', 'Xsd11Group', 'XsdElement', 'Xsd11Element', 'XsdAlternative', 'XsdGlobals', 'XMLSchemaMeta', 'XMLSchemaBase', 'XMLSchema', 'XMLSchema10', 'XMLSchema11' ] ���������������������������xmlschema-1.10.0/xmlschema/validators/assertions.py�������������������������������������������������0000664�0000000�0000000�00000013526�14211403446�0022455�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # import threading from typing import TYPE_CHECKING, cast, Any, Dict, Iterator, Optional, Union from elementpath import XPath2Parser, XPathContext, XPathToken, ElementPathError from ..names import XSD_ASSERT from ..aliases import ElementType, SchemaType, SchemaElementType, NamespacesType from ..xpath import XMLSchemaProtocol, ElementProtocol, ElementPathMixin, XMLSchemaProxy from .exceptions import XMLSchemaNotBuiltError, XMLSchemaValidationError from .xsdbase import XsdComponent from .groups import XsdGroup if TYPE_CHECKING: from ..resources import XMLResource from .attributes import XsdAttributeGroup from .complex_types import XsdComplexType from .elements import XsdElement from .wildcards import XsdAnyElement class XsdAssert(XsdComponent, ElementPathMixin[Union['XsdAssert', SchemaElementType]]): """ Class for XSD *assert* constraint definitions. .. <assert id = ID test = an XPath expression xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local)) {any attributes with non-schema namespace . . .}> Content: (annotation?) </assert> """ parent: 'XsdComplexType' _ADMITTED_TAGS = {XSD_ASSERT} token: Optional[XPathToken] = None parser: Optional[XPath2Parser] = None path = 'true()' def __init__(self, elem: ElementType, schema: SchemaType, parent: 'XsdComplexType', base_type: 'XsdComplexType') -> None: self._xpath_lock = threading.Lock() self.base_type = base_type super(XsdAssert, self).__init__(elem, schema, parent) def __repr__(self) -> str: if len(self.path) < 40: return '%s(test=%r)' % (self.__class__.__name__, self.path) else: return '%s(test=%r)' % (self.__class__.__name__, self.path[:37] + '...') def __getstate__(self) -> Dict[str, Any]: state = self.__dict__.copy() state.pop('_xpath_lock', None) return state def __setstate__(self, state: Any) -> None: self.__dict__.update(state) self._xpath_lock = threading.Lock() def _parse(self) -> None: if self.base_type.is_simple(): self.parse_error("base_type=%r is not a complexType definition" % self.base_type) else: try: self.path = self.elem.attrib['test'].strip() except KeyError as err: self.parse_error(err) if 'xpathDefaultNamespace' in self.elem.attrib: self.xpath_default_namespace = self._parse_xpath_default_namespace(self.elem) else: self.xpath_default_namespace = self.schema.xpath_default_namespace @property def built(self) -> bool: return self.parser is not None and self.token is not None def build(self) -> None: # Assert requires a schema bound parser because select # is on XML elements and with XSD type decoded values self.parser = XPath2Parser( namespaces=self.namespaces, variable_types={'value': self.base_type.sequence_type}, strict=False, default_namespace=self.xpath_default_namespace, schema=self.xpath_proxy, ) try: self.token = self.parser.parse(self.path) except ElementPathError as err: self.parse_error(err) self.token = self.parser.parse('true()') finally: if self.parser.variable_types: self.parser.variable_types.clear() def __call__(self, elem: ElementType, value: Any = None, namespaces: Optional[NamespacesType] = None, source: Optional['XMLResource'] = None, **kwargs: Any) -> Iterator[XMLSchemaValidationError]: if self.parser is None or self.token is None: raise XMLSchemaNotBuiltError(self, "schema bound parser not set") with self._xpath_lock: if not self.parser.is_schema_bound() and self.parser.schema: self.parser.schema.bind_parser(self.parser) if namespaces is None or isinstance(namespaces, dict): _namespaces = namespaces else: _namespaces = dict(namespaces) variables = {'value': None if value is None else self.base_type.text_decode(value)} if source is not None: context = XPathContext(source.root, namespaces=_namespaces, item=elem, variables=variables) else: # If validated from a component (could not work with rooted XPath expressions) context = XPathContext(elem, variables=variables) try: if not self.token.evaluate(context): yield XMLSchemaValidationError(self, obj=elem, reason="assertion test if false") except ElementPathError as err: yield XMLSchemaValidationError(self, obj=elem, reason=str(err)) # For implementing ElementPathMixin def __iter__(self) -> Iterator[Union['XsdElement', 'XsdAnyElement']]: if isinstance(self.parent.content, XsdGroup): yield from self.parent.content.iter_elements() @property def attrib(self) -> 'XsdAttributeGroup': return self.parent.attributes @property def type(self) -> 'XsdComplexType': return self.parent @property def xpath_proxy(self) -> 'XMLSchemaProxy': return XMLSchemaProxy( schema=cast(XMLSchemaProtocol, self.schema), base_element=cast(ElementProtocol, self) ) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/attributes.py�������������������������������������������������0000664�0000000�0000000�00000101032�14211403446�0022437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for XML Schema attributes and attribute groups. """ from decimal import Decimal from elementpath.datatypes import AbstractDateTime, Duration, AbstractBinary from typing import cast, Any, Callable, Union, Dict, List, Optional, \ Iterator, MutableMapping, Tuple from ..exceptions import XMLSchemaValueError from ..names import XSI_NAMESPACE, XSD_ANY_SIMPLE_TYPE, XSD_SIMPLE_TYPE, \ XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, XSD_RESTRICTION, XSD_EXTENSION, \ XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE, \ XSD_ASSERT, XSD_NOTATION_TYPE, XSD_ANNOTATION from ..aliases import ComponentClassType, ElementType, IterDecodeType, \ IterEncodeType, AtomicValueType, SchemaType, DecodedValueType, EncodedValueType from ..helpers import get_namespace, get_qname from .exceptions import XMLSchemaValidationError from .xsdbase import XsdComponent, ValidationMixin from .simple_types import XsdSimpleType from .wildcards import XsdAnyAttribute class XsdAttribute(XsdComponent, ValidationMixin[str, DecodedValueType]): """ Class for XSD 1.0 *attribute* declarations. :ivar type: the XSD simpleType of the attribute. .. <attribute default = string fixed = string form = (qualified | unqualified) id = ID name = NCName ref = QName type = QName use = (optional | prohibited | required) : optional {any attributes with non-schema namespace ...}> Content: (annotation?, simpleType?) </attribute> """ _ADMITTED_TAGS = {XSD_ATTRIBUTE} name: str local_name: str qualified_name: str prefixed_name: str type: XsdSimpleType copy: Callable[['XsdAttribute'], 'XsdAttribute'] qualified: bool = False default: Optional[str] = None fixed: Optional[str] = None form: Optional[str] = None use: str = 'optional' inheritable: bool = False # For XSD 1.1 attributes, always False for XSD 1.0 attributes. def _parse(self) -> None: attrib = self.elem.attrib if 'use' in attrib and self.parent is not None and \ attrib['use'] in {'optional', 'prohibited', 'required'}: self.use = attrib['use'] if self._parse_reference(): try: xsd_attribute = self.maps.lookup_attribute(self.name) except LookupError: self.type = self.any_simple_type self.parse_error("unknown attribute {!r}".format(self.name)) else: self.ref = xsd_attribute self.type = xsd_attribute.type self.qualified = xsd_attribute.qualified self.form = xsd_attribute.form if xsd_attribute.default is not None and 'default' not in attrib: self.default = xsd_attribute.default if xsd_attribute.fixed is not None: if 'fixed' not in attrib: self.fixed = xsd_attribute.fixed elif xsd_attribute.fixed != attrib['fixed']: msg = "referenced attribute has a different fixed value {!r}" self.parse_error(msg.format(xsd_attribute.fixed)) for attribute in ('form', 'type'): if attribute in self.elem.attrib: self.parse_error("attribute {!r} is not allowed when " "attribute reference is used".format(attribute)) else: if 'form' in attrib: self.form = attrib['form'] if self.parent is not None and self.form == 'qualified': self.qualified = True elif self.schema.attribute_form_default == 'qualified': self.qualified = True try: name = attrib['name'] except KeyError: pass else: if name == 'xmlns': self.parse_error("an attribute name must be different from 'xmlns'") if self.parent is None or self.qualified: if self.target_namespace == XSI_NAMESPACE and \ name not in {'nil', 'type', 'schemaLocation', 'noNamespaceSchemaLocation'}: self.parse_error("cannot add attributes in %r namespace" % XSI_NAMESPACE) self.name = get_qname(self.target_namespace, name) else: self.name = name child = self._parse_child_component(self.elem) if 'type' in attrib: try: type_qname = self.schema.resolve_qname(attrib['type']) except (KeyError, ValueError, RuntimeError) as err: self.type = self.any_simple_type self.parse_error(err) else: try: self.type = cast(XsdSimpleType, self.maps.lookup_type(type_qname)) except LookupError as err: self.type = self.any_simple_type self.parse_error(err) if child is not None and child.tag == XSD_SIMPLE_TYPE: self.parse_error("ambiguous type definition for XSD attribute") elif child is not None: # No 'type' attribute in declaration, parse for child local simpleType self.type = self.schema.simple_type_factory(child, self.schema, self) else: # Empty declaration means xsdAnySimpleType self.type = self.any_simple_type if not isinstance(self.type, XsdSimpleType): self.type = self.any_simple_type self.parse_error("XSD attribute's type must be a simpleType") # Check value constraints if 'default' in attrib: self.default = attrib['default'] if 'fixed' in attrib: self.parse_error("'default' and 'fixed' attributes are mutually exclusive") if self.use != 'optional': self.parse_error("the attribute 'use' must be 'optional' " "if the attribute 'default' is present") if not self.type.is_valid(self.default): msg = "default value {!r} is not compatible with attribute's type" self.parse_error(msg.format(self.default)) elif self.type.is_key() and self.xsd_version == '1.0': self.parse_error("xs:ID key attributes cannot have a default value") elif 'fixed' in attrib: self.fixed = attrib['fixed'] if not self.type.is_valid(self.fixed): msg = "fixed value {!r} is not compatible with attribute's type" self.parse_error(msg.format(self.fixed)) elif self.type.is_key() and self.xsd_version == '1.0': self.parse_error("xs:ID key attributes cannot have a fixed value") @property def built(self) -> bool: return True @property def validation_attempted(self) -> str: return 'full' @property def scope(self) -> str: """The scope of the attribute declaration that can be 'global' or 'local'.""" return 'global' if self.parent is None else 'local' @property def value_constraint(self) -> Optional[str]: """The fixed or the default value if either is defined, `None` otherwise.""" return self.fixed if self.fixed is not None else self.default def is_optional(self) -> bool: return self.use == 'optional' def is_required(self) -> bool: return self.use == 'required' def is_prohibited(self) -> bool: return self.use == 'prohibited' def is_empty(self) -> bool: return self.fixed == '' or self.type.is_empty() def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self if self.ref is None and self.type.parent is not None: yield from self.type.iter_components(xsd_classes) def data_value(self, text: str) -> AtomicValueType: """Returns the decoded data value of the provided text as XPath fn:data().""" return cast(AtomicValueType, self.decode(text, validation='skip')) def iter_decode(self, obj: str, validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[DecodedValueType]: if obj is None and self.default is not None: obj = self.default if self.type.is_notation(): if self.type.name == XSD_NOTATION_TYPE: msg = "cannot validate against xs:NOTATION directly, " \ "only against a subtype with an enumeration facet" yield self.validation_error(validation, msg, obj, **kwargs) elif not self.type.enumeration: msg = "missing enumeration facet in xs:NOTATION subtype" yield self.validation_error(validation, msg, obj, **kwargs) if self.fixed is not None: if obj is None: obj = self.fixed elif obj != self.fixed and \ self.type.text_decode(obj) != self.type.text_decode(self.fixed): msg = "attribute {!r} has a fixed value {!r}".format(self.name, self.fixed) yield self.validation_error(validation, msg, obj, **kwargs) for value in self.type.iter_decode(obj, validation, **kwargs): if isinstance(value, XMLSchemaValidationError): value.reason = 'attribute {}={!r}: {}'.format( self.prefixed_name, obj, value.reason ) yield value continue elif 'value_hook' in kwargs: yield kwargs['value_hook'](value, self.type) elif isinstance(value, (int, float, list)) or value is None: yield value elif isinstance(value, str): if value.startswith('{') and self.type.is_qname(): yield obj else: yield value elif isinstance(value, Decimal): try: yield kwargs['decimal_type'](value) except (KeyError, TypeError): yield value elif isinstance(value, (AbstractDateTime, Duration)): yield value if kwargs.get('datetime_types') else obj.strip() elif isinstance(value, AbstractBinary) and not kwargs.get('binary_types'): yield str(value) else: yield value break # pragma: no cover def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[Union[EncodedValueType]]: yield from self.type.iter_encode(obj, validation, **kwargs) class Xsd11Attribute(XsdAttribute): """ Class for XSD 1.1 *attribute* declarations. .. <attribute default = string fixed = string form = (qualified | unqualified) id = ID name = NCName ref = QName targetNamespace = anyURI type = QName use = (optional | prohibited | required) : optional inheritable = boolean {any attributes with non-schema namespace . . .}> Content: (annotation?, simpleType?) </attribute> """ _target_namespace: Optional[str] = None @property def target_namespace(self) -> str: if self._target_namespace is not None: return self._target_namespace elif self.ref is not None: return self.ref.target_namespace else: return self.schema.target_namespace def _parse(self) -> None: super()._parse() if self.use == 'prohibited' and 'fixed' in self.elem.attrib: self.parse_error("attribute 'fixed' with use=prohibited is not allowed in XSD 1.1") if 'inheritable' in self.elem.attrib: if self.elem.attrib['inheritable'].strip() in {'true', '1'}: self.inheritable = True self._parse_target_namespace() class XsdAttributeGroup( MutableMapping[Optional[str], Union[XsdAttribute, XsdAnyAttribute]], XsdComponent, ValidationMixin[MutableMapping[str, str], List[Tuple[str, Any]]] ): """ Class for XSD *attributeGroup* definitions. .. <attributeGroup id = ID name = NCName ref = QName {any attributes with non-schema namespace . . .}> Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) </attributeGroup> """ _ADMITTED_TAGS = { XSD_ATTRIBUTE_GROUP, XSD_COMPLEX_TYPE, XSD_RESTRICTION, XSD_EXTENSION, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE } copy: Callable[['XsdAttributeGroup'], 'XsdAttributeGroup'] def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent] = None, derivation: Optional[str] = None, base_attributes: Optional['XsdAttributeGroup'] = None) -> None: self._attribute_group: Dict[Optional[str], Union[XsdAttribute, XsdAnyAttribute]] = {} self.derivation = derivation self.base_attributes = base_attributes XsdComponent.__init__(self, elem, schema, parent) def __repr__(self) -> str: if self.name is not None: return '%s(name=%r)' % (self.__class__.__name__, self.name) elif self: names = [a if a.name is None else a.name for a in self.values()] return '%s(%r)' % (self.__class__.__name__, names) else: return '%s()' % self.__class__.__name__ # Implementation of abstract methods def __getitem__(self, key: Optional[str]) -> Union[XsdAttribute, XsdAnyAttribute]: return self._attribute_group[key] def __setitem__(self, key: Optional[str], value: Union[XsdAttribute, XsdAnyAttribute]) -> None: if value.name != key: raise XMLSchemaValueError("%r name and key %r mismatch" % (value.name, key)) self._attribute_group[key] = value def __delitem__(self, key: Optional[str]) -> None: del self._attribute_group[key] def __iter__(self) -> Iterator[Optional[str]]: if None in self._attribute_group: # Put AnyAttribute ('None' key) at the end of iteration yield from sorted(self._attribute_group, key=lambda x: (x is None, x)) else: yield from self._attribute_group def __len__(self) -> int: return len(self._attribute_group) def _parse(self) -> None: if self.elem.tag == XSD_ATTRIBUTE_GROUP: if self.parent is not None: return # Skip parsing dummy instances try: self.name = get_qname(self.target_namespace, self.elem.attrib['name']) except KeyError: return else: if self.schema.default_attributes == self.name and self.xsd_version > '1.0': self.schema.default_attributes = self any_attribute = None attribute_group_refs = [] attributes: Dict[Optional[str], Union[XsdAttribute, XsdAnyAttribute]] = {} for child in self.elem: if child.tag == XSD_ANNOTATION or callable(child.tag): continue # pragma: no cover elif any_attribute is not None: if child.tag == XSD_ANY_ATTRIBUTE: self.parse_error("more anyAttribute declarations in the same attribute group") elif child.tag != XSD_ASSERT: self.parse_error("another declaration after anyAttribute") elif child.tag == XSD_ANY_ATTRIBUTE: any_attribute = self.schema.xsd_any_attribute_class(child, self.schema, self) if None in attributes: attributes[None] = attr = attributes[None].copy() assert isinstance(attr, XsdAnyAttribute) attr.intersection(any_attribute) else: attributes[None] = any_attribute elif child.tag == XSD_ATTRIBUTE: attribute = self.schema.xsd_attribute_class(child, self.schema, self) if attribute.name in attributes: self.parse_error("multiple declaration for attribute " "{!r}".format(attribute.name)) elif attribute.use != 'prohibited' or self.elem.tag != XSD_ATTRIBUTE_GROUP: attributes[attribute.name] = attribute elif child.tag == XSD_ATTRIBUTE_GROUP: try: ref = child.attrib['ref'] except KeyError: self.parse_error("the attribute 'ref' is required " "in a local attributeGroup") continue try: attribute_group_qname = self.schema.resolve_qname(ref) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) else: if attribute_group_qname in attribute_group_refs: self.parse_error("duplicated attributeGroup %r" % ref) elif self.redefine is not None: if attribute_group_qname == self.name: if attribute_group_refs: self.parse_error("in a redefinition the reference " "to itself must be the first") attribute_group_refs.append(attribute_group_qname) attributes.update(self._attribute_group) continue elif not attribute_group_refs: # May be an attributeGroup restriction with a ref to another group if not any(e.tag == XSD_ATTRIBUTE_GROUP and ref == e.get('ref') for e in self.redefine.elem): self.parse_error("attributeGroup ref=%r is not " "in the redefined group" % ref) elif attribute_group_qname == self.name and self.xsd_version == '1.0': self.parse_error("Circular attribute groups not allowed in XSD 1.0") attribute_group_refs.append(attribute_group_qname) try: ref_attributes = self.maps.lookup_attribute_group(attribute_group_qname) except LookupError: self.parse_error("unknown attribute group %r" % child.attrib['ref']) else: if not isinstance(ref_attributes, tuple): for name, base_attr in ref_attributes.items(): if name not in attributes: attributes[name] = base_attr elif name is not None: if base_attr is not attributes[name]: self.parse_error( f"multiple declaration of attribute {name!r}" ) else: assert isinstance(base_attr, XsdAnyAttribute) attributes[None] = attr = attributes[None].copy() assert isinstance(attr, XsdAnyAttribute) attr.intersection(base_attr) elif self.xsd_version == '1.0': self.parse_error( "Circular reference found between attribute groups " "{!r} and {!r}".format(self.name, attribute_group_qname) ) elif self.name is not None: self.parse_error("(attribute | attributeGroup) expected, found %r." % child) # Check and copy base attributes if self.base_attributes is not None: wildcard = self.base_attributes.get(None) for name, attr in attributes.items(): if name not in self.base_attributes: if self.derivation != 'restriction': continue elif wildcard is None or not wildcard.is_matching(name, self.default_namespace): self.parse_error("Unexpected attribute %r in restriction" % name) continue base_attr = self.base_attributes[name] if isinstance(attr, XsdAnyAttribute): assert name is None, "name key resolves to an xs:anyAttribute" assert isinstance(base_attr, XsdAnyAttribute), "invalid base attribute" if self.derivation == 'extension': try: attr.union(base_attr) except ValueError as err: self.parse_error(err) elif not attr.is_restriction(base_attr): self.parse_error("Attribute wildcard is not a restriction " "of the base wildcard") continue assert name is not None, "None key resolves to an xs:attribute" assert isinstance(base_attr, XsdAttribute), "invalid base attribute" if self.derivation == 'restriction' and attr.type.name != XSD_ANY_SIMPLE_TYPE and \ not attr.type.is_derived(base_attr.type, 'restriction'): self.parse_error("Attribute type is not a restriction " "of the base attribute type") if base_attr.use != 'optional' and attr.use == 'optional' or \ base_attr.use == 'required' and attr.use != 'required': self.parse_error("Attribute %r: unmatched attribute use in restriction" % name) if base_attr.fixed is not None: if attr.fixed is None or attr.type.normalize(attr.fixed) != \ base_attr.type.normalize(base_attr.fixed): self.parse_error("Attribute %r: derived attribute " "has a different fixed value" % name) if base_attr.inheritable is not attr.inheritable: msg = "Attribute %r: attribute 'inheritable' value change in restriction" self.parse_error(msg % name) if self.redefine is not None: pass # In case of redefinition do not copy base attributes else: self._attribute_group.update(self.base_attributes.items()) elif self.redefine is not None and not attribute_group_refs: for name, attr in self._attribute_group.items(): if name is None: continue elif name not in attributes: if attr.use == 'required': self.parse_error("Missing required attribute %r in " "redefinition restriction" % name) continue if attr.use != 'optional' and attributes[name].use != attr.use: self.parse_error("Attribute %r: unmatched attribute use in redefinition" % name) if attr.fixed is not None and attributes[name].fixed is None: self.parse_error("Attribute %r: redefinition remove fixed constraint" % name) pos = 0 keys = list(self._attribute_group.keys()) for name in attributes: try: next_pos = keys.index(name) except ValueError: self.parse_error("Redefinition restriction contains " "additional attribute %r" % name) else: if next_pos < pos: self.parse_error("Wrong attribute order in redefinition restriction") break pos = next_pos self.clear() self._attribute_group.update(attributes) if None in self._attribute_group and None not in attributes \ and self.derivation == 'restriction': wildcard = self._attribute_group[None].copy() wildcard.namespace = wildcard.not_namespace = wildcard.not_qname = () self._attribute_group[None] = wildcard if self.xsd_version == '1.0': has_key = False for attr in self._attribute_group.values(): if attr.type is not None and attr.type.is_key(): if has_key: self.parse_error("multiple ID attributes not allowed for XSD 1.0") break has_key = True elif self.parent is None and self.schema.default_attributes == self.name: self.schema.default_attributes = self @property def built(self) -> bool: return True def parse_error(self, error: Union[str, Exception], elem: Optional[ElementType] = None, validation: Optional[str] = None) -> None: if self.parent is None: super().parse_error(error, elem, validation) else: self.parent.parse_error(error, elem, validation) def iter_required(self) -> Iterator[str]: for k, v in self._attribute_group.items(): if isinstance(v, XsdAttribute) and k is not None: if v.use == 'required': yield k def iter_value_constraints(self, use_defaults: bool = True) -> Iterator[Tuple[str, str]]: if use_defaults: for k, v in self._attribute_group.items(): if v.fixed is not None and k: yield k, v.fixed elif v.default is not None and k: yield k, v.default else: for k, v in self._attribute_group.items(): if v.fixed is not None and k: yield k, v.fixed def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self for attr in self.values(): if attr.parent is not None: yield from attr.iter_components(xsd_classes) def iter_decode(self, obj: MutableMapping[str, str], validation: str = 'lax', **kwargs: Any) -> IterDecodeType[List[Tuple[str, Any]]]: if not obj and not self: return for name in filter(lambda x: x not in obj, self.iter_required()): reason = "missing required attribute {!r}".format(name) yield self.validation_error(validation, reason, obj, **kwargs) kwargs['level'] = kwargs.get('level', 0) + 1 try: use_defaults = kwargs['use_defaults'] except KeyError: use_defaults = True additional_attrs = [ (k, v) for k, v in self.iter_value_constraints(use_defaults) if k not in obj ] if additional_attrs: obj = {k: v for k, v in obj.items()} obj.update(additional_attrs) if self.xsd_version == '1.0': kwargs['id_list'] = [] filler = kwargs.get('filler') result_list: List[Tuple[str, DecodedValueType]] = [] value: Any for name, value in obj.items(): try: xsd_attribute = self._attribute_group[name] except KeyError: if get_namespace(name) == XSI_NAMESPACE: try: xsd_attribute = self.maps.lookup_attribute(name) except LookupError: try: xsd_attribute = self._attribute_group[None] # None == anyAttribute value = (name, value) except KeyError: reason = "%r is not an attribute of the XSI namespace." % name yield self.validation_error(validation, reason, obj, **kwargs) continue else: try: xsd_attribute = self._attribute_group[None] # None == anyAttribute value = (name, value) except KeyError: reason = "%r attribute not allowed for element." % name yield self.validation_error(validation, reason, obj, **kwargs) continue else: if xsd_attribute.use == 'prohibited' and \ (None not in self or not self._attribute_group[None].is_matching(name)): reason = "use of attribute %r is prohibited" % name yield self.validation_error(validation, reason, obj, **kwargs) for result in xsd_attribute.iter_decode(value, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result elif result is None and filler is not None: result_list.append((name, filler(xsd_attribute))) break else: result_list.append((name, result)) break if kwargs.get('fill_missing'): if filler is None: result_list.extend((k, None) for k in self._attribute_group if k is not None and k not in obj) else: result_list.extend((k, filler(v)) for k, v in self._attribute_group.items() if k is not None and k not in obj) yield result_list def iter_encode(self, obj: MutableMapping[str, Any], validation: str = 'lax', **kwargs: Any) -> IterEncodeType[List[Tuple[str, Union[str, List[str]]]]]: if not obj and not self: return for name in filter(lambda x: x not in obj, self.iter_required()): reason = "missing required attribute {!r}".format(name) yield self.validation_error(validation, reason, obj, **kwargs) try: use_defaults = kwargs['use_defaults'] except KeyError: use_defaults = True result_list = [] for name, value in obj.items(): try: xsd_attribute = self._attribute_group[name] except KeyError: namespace = get_namespace(name) or self.target_namespace if namespace == XSI_NAMESPACE: try: xsd_attribute = self.maps.lookup_attribute(name) except LookupError: try: xsd_attribute = self._attribute_group[None] # None == anyAttribute value = (name, value) except KeyError: reason = "%r is not an attribute of the XSI namespace." % name yield self.validation_error(validation, reason, obj, **kwargs) continue else: try: xsd_attribute = self._attribute_group[None] # None == anyAttribute value = (name, value) except KeyError: reason = "%r attribute not allowed for element." % name yield self.validation_error(validation, reason, obj, **kwargs) continue for result in xsd_attribute.iter_encode(value, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: if result is not None: result_list.append((name, result)) break result_list.extend( (k, v) for k, v in self.iter_value_constraints(use_defaults) if k not in obj ) yield result_list ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/builtins.py���������������������������������������������������0000664�0000000�0000000�00000046640�14211403446�0022117�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains definitions and a factory function for XSD builtin datatypes. Only atomic builtins are created, the list builtins types ('NMTOKENS', 'ENTITIES', 'IDREFS') are created using the XSD 1.0 meta-schema or with and additional base schema for XSD 1.1. """ from decimal import Decimal from elementpath import datatypes from typing import cast, Any, Dict, Optional, Type, Tuple, Union from ..exceptions import XMLSchemaValueError from ..names import XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_ENUMERATION, \ XSD_PATTERN, XSD_WHITE_SPACE, XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_MAX_INCLUSIVE, \ XSD_MAX_EXCLUSIVE, XSD_TOTAL_DIGITS, XSD_FRACTION_DIGITS, XSD_EXPLICIT_TIMEZONE, \ XSD_STRING, XSD_NORMALIZED_STRING, XSD_NAME, XSD_NCNAME, XSD_QNAME, XSD_TOKEN, \ XSD_NMTOKEN, XSD_ID, XSD_IDREF, XSD_LANGUAGE, XSD_DECIMAL, XSD_DOUBLE, XSD_FLOAT, \ XSD_INTEGER, XSD_BYTE, XSD_SHORT, XSD_INT, XSD_LONG, XSD_UNSIGNED_BYTE, \ XSD_UNSIGNED_SHORT, XSD_UNSIGNED_INT, XSD_UNSIGNED_LONG, XSD_POSITIVE_INTEGER, \ XSD_NEGATIVE_INTEGER, XSD_NON_NEGATIVE_INTEGER, XSD_NON_POSITIVE_INTEGER, \ XSD_GDAY, XSD_GMONTH, XSD_GMONTH_DAY, XSD_GYEAR, XSD_GYEAR_MONTH, XSD_TIME, XSD_DATE, \ XSD_DATETIME, XSD_DATE_TIME_STAMP, XSD_ENTITY, XSD_ANY_URI, XSD_BOOLEAN, \ XSD_DURATION, XSD_DAY_TIME_DURATION, XSD_YEAR_MONTH_DURATION, XSD_BASE64_BINARY, \ XSD_HEX_BINARY, XSD_NOTATION_TYPE, XSD_ERROR, XSD_ASSERTION, XSD_SIMPLE_TYPE, \ XSD_ANY_TYPE, XSD_ANY_ATOMIC_TYPE, XSD_ANY_SIMPLE_TYPE from ..etree import etree_element from ..aliases import ElementType, SchemaType, BaseXsdType from .helpers import decimal_validator, qname_validator, byte_validator, \ short_validator, int_validator, long_validator, unsigned_byte_validator, \ unsigned_short_validator, unsigned_int_validator, unsigned_long_validator, \ negative_int_validator, positive_int_validator, non_positive_int_validator, \ non_negative_int_validator, hex_binary_validator, base64_binary_validator, \ error_type_validator, boolean_to_python, python_to_boolean from .facets import XSD_10_FACETS_BUILDERS, XSD_11_FACETS_BUILDERS from .simple_types import XsdSimpleType, XsdAtomicBuiltin # # Admitted facets sets for XSD atomic types STRING_FACETS = { XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_PATTERN, XSD_ENUMERATION, XSD_WHITE_SPACE, XSD_ASSERTION } BOOLEAN_FACETS = {XSD_PATTERN, XSD_WHITE_SPACE, XSD_ASSERTION} FLOAT_FACETS = { XSD_PATTERN, XSD_ENUMERATION, XSD_WHITE_SPACE, XSD_MAX_INCLUSIVE, XSD_MAX_EXCLUSIVE, XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_ASSERTION } DECIMAL_FACETS = { XSD_TOTAL_DIGITS, XSD_FRACTION_DIGITS, XSD_PATTERN, XSD_ENUMERATION, XSD_WHITE_SPACE, XSD_MAX_INCLUSIVE, XSD_MAX_EXCLUSIVE, XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_ASSERTION } DATETIME_FACETS = { XSD_PATTERN, XSD_ENUMERATION, XSD_WHITE_SPACE, XSD_MAX_INCLUSIVE, XSD_MAX_EXCLUSIVE, XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_ASSERTION, XSD_EXPLICIT_TIMEZONE } # # Element facets instances for builtin types. PRESERVE_WHITE_SPACE_ELEMENT = etree_element(XSD_WHITE_SPACE, value='preserve') COLLAPSE_WHITE_SPACE_ELEMENT = etree_element(XSD_WHITE_SPACE, value='collapse') REPLACE_WHITE_SPACE_ELEMENT = etree_element(XSD_WHITE_SPACE, value='replace') XSD10_FLOAT_PATTERN_ELEMENT = etree_element( XSD_PATTERN, value=r"(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)([Ee](\+|-)?[0-9]+)?|INF|-INF|NaN" ) XSD11_FLOAT_PATTERN_ELEMENT = etree_element( XSD_PATTERN, value=r"(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)([Ee](\+|-)?[0-9]+)?|(\+|-)?INF|NaN" ) XSD_COMMON_BUILTIN_TYPES: Tuple[Dict[str, Any], ...] = ( # *********************** # *** Primitive types *** # *********************** # --- String Types --- { 'name': XSD_STRING, 'python_type': str, 'admitted_facets': STRING_FACETS, 'facets': [PRESERVE_WHITE_SPACE_ELEMENT], }, # character string # --- Numerical Types --- { 'name': XSD_DECIMAL, 'python_type': (Decimal, str, int, float), 'admitted_facets': DECIMAL_FACETS, 'to_python': datatypes.DecimalProxy, 'facets': [decimal_validator, COLLAPSE_WHITE_SPACE_ELEMENT], }, # decimal number # --- Dates and Times (not year related) --- { 'name': XSD_GDAY, 'python_type': (datatypes.GregorianDay, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianDay.fromstring, }, # DD { 'name': XSD_GMONTH, 'python_type': (datatypes.GregorianMonth, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianMonth.fromstring, }, # MM { 'name': XSD_GMONTH_DAY, 'python_type': (datatypes.GregorianMonthDay, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianMonthDay.fromstring, }, # MM-DD { 'name': XSD_TIME, 'python_type': (datatypes.Time, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.Time.fromstring, }, # hh:mm:ss { 'name': XSD_DURATION, 'python_type': (datatypes.Duration, str), 'admitted_facets': FLOAT_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.Duration.fromstring, }, # PnYnMnDTnHnMnS # Other primitive types { 'name': XSD_QNAME, 'python_type': str, 'admitted_facets': STRING_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT, qname_validator], }, # prf:name (the prefix needs to be qualified with an in-scope namespace) { 'name': XSD_NOTATION_TYPE, 'python_type': str, 'admitted_facets': STRING_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], }, # type for NOTATION attributes: QNames of xs:notation declarations as value space. { 'name': XSD_ANY_URI, 'python_type': str, 'admitted_facets': STRING_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], }, # absolute or relative uri (RFC 2396) { 'name': XSD_BOOLEAN, 'python_type': bool, 'admitted_facets': BOOLEAN_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': boolean_to_python, 'from_python': python_to_boolean, }, # true/false or 1/0 { 'name': XSD_BASE64_BINARY, 'python_type': (datatypes.Base64Binary, str, bytes), 'admitted_facets': STRING_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT, base64_binary_validator], }, # base64 encoded binary value { 'name': XSD_HEX_BINARY, 'python_type': (datatypes.HexBinary, str, bytes), 'admitted_facets': STRING_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT, hex_binary_validator], }, # hexadecimal encoded binary value # ********************* # *** Derived types *** # ********************* # --- String Types --- { 'name': XSD_NORMALIZED_STRING, 'python_type': str, 'base_type': XSD_STRING, 'facets': [REPLACE_WHITE_SPACE_ELEMENT], }, # line breaks are normalized { 'name': XSD_TOKEN, 'python_type': str, 'base_type': XSD_NORMALIZED_STRING, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], }, # whitespaces are normalized { 'name': XSD_LANGUAGE, 'python_type': str, 'base_type': XSD_TOKEN, 'facets': [etree_element(XSD_PATTERN, value=r"[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*")] }, # language codes { 'name': XSD_NAME, 'python_type': str, 'base_type': XSD_TOKEN, 'facets': [etree_element(XSD_PATTERN, value=r"\i\c*")] }, # not starting with a digit { 'name': XSD_NCNAME, 'python_type': str, 'base_type': XSD_NAME, 'facets': [etree_element(XSD_PATTERN, value=r"[\i-[:]][\c-[:]]*")] }, # cannot contain colons { 'name': XSD_ID, 'python_type': str, 'base_type': XSD_NCNAME }, # unique identification in document (attribute only) { 'name': XSD_IDREF, 'python_type': str, 'base_type': XSD_NCNAME }, # reference to ID field in document (attribute only) { 'name': XSD_ENTITY, 'python_type': str, 'base_type': XSD_NCNAME }, # reference to entity (attribute only) { 'name': XSD_NMTOKEN, 'python_type': str, 'base_type': XSD_TOKEN, 'facets': [etree_element(XSD_PATTERN, value=r"\c+")] }, # should not contain whitespace (attribute only) # --- Numerical derived types --- { 'name': XSD_INTEGER, 'python_type': int, 'base_type': XSD_DECIMAL }, # any integer value { 'name': XSD_LONG, 'python_type': int, 'base_type': XSD_INTEGER, 'facets': [long_validator, etree_element(XSD_MIN_INCLUSIVE, value='-9223372036854775808'), etree_element(XSD_MAX_INCLUSIVE, value='9223372036854775807')] }, # signed 128 bit value { 'name': XSD_INT, 'python_type': int, 'base_type': XSD_LONG, 'facets': [int_validator, etree_element(XSD_MIN_INCLUSIVE, value='-2147483648'), etree_element(XSD_MAX_INCLUSIVE, value='2147483647')] }, # signed 64 bit value { 'name': XSD_SHORT, 'python_type': int, 'base_type': XSD_INT, 'facets': [short_validator, etree_element(XSD_MIN_INCLUSIVE, value='-32768'), etree_element(XSD_MAX_INCLUSIVE, value='32767')] }, # signed 32 bit value { 'name': XSD_BYTE, 'python_type': int, 'base_type': XSD_SHORT, 'facets': [byte_validator, etree_element(XSD_MIN_INCLUSIVE, value='-128'), etree_element(XSD_MAX_INCLUSIVE, value='127')] }, # signed 8 bit value { 'name': XSD_NON_NEGATIVE_INTEGER, 'python_type': int, 'base_type': XSD_INTEGER, 'facets': [non_negative_int_validator, etree_element(XSD_MIN_INCLUSIVE, value='0')] }, # only zero and more value allowed [>= 0] { 'name': XSD_POSITIVE_INTEGER, 'python_type': int, 'base_type': XSD_NON_NEGATIVE_INTEGER, 'facets': [positive_int_validator, etree_element(XSD_MIN_INCLUSIVE, value='1')] }, # only positive value allowed [> 0] { 'name': XSD_UNSIGNED_LONG, 'python_type': int, 'base_type': XSD_NON_NEGATIVE_INTEGER, 'facets': [unsigned_long_validator, etree_element(XSD_MAX_INCLUSIVE, value='18446744073709551615')] }, # unsigned 128 bit value { 'name': XSD_UNSIGNED_INT, 'python_type': int, 'base_type': XSD_UNSIGNED_LONG, 'facets': [unsigned_int_validator, etree_element(XSD_MAX_INCLUSIVE, value='4294967295')] }, # unsigned 64 bit value { 'name': XSD_UNSIGNED_SHORT, 'python_type': int, 'base_type': XSD_UNSIGNED_INT, 'facets': [unsigned_short_validator, etree_element(XSD_MAX_INCLUSIVE, value='65535')] }, # unsigned 32 bit value { 'name': XSD_UNSIGNED_BYTE, 'python_type': int, 'base_type': XSD_UNSIGNED_SHORT, 'facets': [unsigned_byte_validator, etree_element(XSD_MAX_INCLUSIVE, value='255')] }, # unsigned 8 bit value { 'name': XSD_NON_POSITIVE_INTEGER, 'python_type': int, 'base_type': XSD_INTEGER, 'facets': [non_positive_int_validator, etree_element(XSD_MAX_INCLUSIVE, value='0')] }, # only zero and smaller value allowed [<= 0] { 'name': XSD_NEGATIVE_INTEGER, 'python_type': int, 'base_type': XSD_NON_POSITIVE_INTEGER, 'facets': [negative_int_validator, etree_element(XSD_MAX_INCLUSIVE, value='-1')] }, # only negative value allowed [< 0] ) XSD_10_BUILTIN_TYPES: Tuple[Dict[str, Any], ...] = XSD_COMMON_BUILTIN_TYPES + ( { 'name': XSD_DOUBLE, 'python_type': float, 'admitted_facets': FLOAT_FACETS, 'facets': [XSD10_FLOAT_PATTERN_ELEMENT, COLLAPSE_WHITE_SPACE_ELEMENT], }, # 64 bit floating point { 'name': XSD_FLOAT, 'python_type': float, 'admitted_facets': FLOAT_FACETS, 'facets': [XSD10_FLOAT_PATTERN_ELEMENT, COLLAPSE_WHITE_SPACE_ELEMENT], }, # 32 bit floating point # --- Year related primitive types (year 0 not allowed) --- { 'name': XSD_DATETIME, 'python_type': (datatypes.DateTime10, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.DateTime10.fromstring, }, # [-][Y*]YYYY-MM-DD[Thh:mm:ss] { 'name': XSD_DATE, 'python_type': (datatypes.Date10, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.Date10.fromstring, }, # [-][Y*]YYYY-MM-DD { 'name': XSD_GYEAR, 'python_type': (datatypes.GregorianYear10, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianYear10.fromstring, }, # [-][Y*]YYYY { 'name': XSD_GYEAR_MONTH, 'python_type': (datatypes.GregorianYearMonth10, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianYearMonth10.fromstring, }, # [-][Y*]YYYY-MM ) XSD_11_BUILTIN_TYPES: Tuple[Dict[str, Any], ...] = XSD_COMMON_BUILTIN_TYPES + ( { 'name': XSD_DOUBLE, 'python_type': float, 'admitted_facets': FLOAT_FACETS, 'facets': [XSD11_FLOAT_PATTERN_ELEMENT, COLLAPSE_WHITE_SPACE_ELEMENT], }, # 64 bit floating point { 'name': XSD_FLOAT, 'python_type': float, 'admitted_facets': FLOAT_FACETS, 'facets': [XSD11_FLOAT_PATTERN_ELEMENT, COLLAPSE_WHITE_SPACE_ELEMENT], }, # 32 bit floating point # --- Year related primitive types (year 0 allowed and mapped to 1 BCE) --- { 'name': XSD_DATETIME, 'python_type': (datatypes.DateTime, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.DateTime.fromstring, }, # [-][Y*]YYYY-MM-DD[Thh:mm:ss] { 'name': XSD_DATE, 'python_type': (datatypes.Date, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.Date.fromstring, }, # [-][Y*]YYYY-MM-DD { 'name': XSD_GYEAR, 'python_type': (datatypes.GregorianYear, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianYear.fromstring, }, # [-][Y*]YYYY { 'name': XSD_GYEAR_MONTH, 'python_type': (datatypes.GregorianYearMonth, str), 'admitted_facets': DATETIME_FACETS, 'facets': [COLLAPSE_WHITE_SPACE_ELEMENT], 'to_python': datatypes.GregorianYearMonth.fromstring, }, # [-][Y*]YYYY-MM # --- Datetime derived types (XSD 1.1) --- { 'name': XSD_DATE_TIME_STAMP, 'python_type': (datatypes.DateTimeStamp, str), 'base_type': XSD_DATETIME, 'to_python': datatypes.DateTime.fromstring, 'facets': [etree_element(XSD_EXPLICIT_TIMEZONE, value='required')], }, # [-][Y*]YYYY-MM-DD[Thh:mm:ss] with required timezone { 'name': XSD_DAY_TIME_DURATION, 'python_type': (datatypes.DayTimeDuration, str), 'base_type': XSD_DURATION, 'to_python': datatypes.DayTimeDuration.fromstring, }, # PnYnMnDTnHnMnS with month an year equal to 0 { 'name': XSD_YEAR_MONTH_DURATION, 'python_type': (datatypes.YearMonthDuration, str), 'base_type': XSD_DURATION, 'to_python': datatypes.YearMonthDuration.fromstring, }, # PnYnMnDTnHnMnS with day and time equals to 0 # --- xs:error primitive type (XSD 1.1) --- { 'name': XSD_ERROR, 'python_type': type(None), 'admitted_facets': (), 'facets': [error_type_validator], }, # xs:error has no value space and no lexical space ) def xsd_builtin_types_factory( meta_schema: SchemaType, xsd_types: Dict[str, Union[BaseXsdType, Tuple[ElementType, SchemaType]]], atomic_builtin_class: Optional[Type[XsdAtomicBuiltin]] = None) -> None: """ Builds the dictionary for XML Schema built-in types mapping. """ atomic_builtin_class = atomic_builtin_class or XsdAtomicBuiltin if meta_schema.XSD_VERSION == '1.1': builtin_types = XSD_11_BUILTIN_TYPES facets_map = XSD_11_FACETS_BUILDERS else: builtin_types = XSD_10_BUILTIN_TYPES facets_map = XSD_10_FACETS_BUILDERS # # Special builtin types. # # xs:anyType # Ref: https://www.w3.org/TR/xmlschema11-1/#builtin-ctd xsd_types[XSD_ANY_TYPE] = meta_schema.create_any_type() # xs:anySimpleType # Ref: https://www.w3.org/TR/xmlschema11-2/#builtin-stds xsd_any_simple_type = xsd_types[XSD_ANY_SIMPLE_TYPE] = XsdSimpleType( elem=etree_element(XSD_SIMPLE_TYPE, name=XSD_ANY_SIMPLE_TYPE), schema=meta_schema, parent=None, name=XSD_ANY_SIMPLE_TYPE ) # xs:anyAtomicType # Ref: https://www.w3.org/TR/xmlschema11-2/#builtin-stds xsd_types[XSD_ANY_ATOMIC_TYPE] = meta_schema.xsd_atomic_restriction_class( elem=etree_element(XSD_SIMPLE_TYPE, name=XSD_ANY_ATOMIC_TYPE), schema=meta_schema, parent=None, name=XSD_ANY_ATOMIC_TYPE, base_type=xsd_any_simple_type, ) for item in builtin_types: item = item.copy() name: str = item['name'] try: value = cast(Tuple[ElementType, SchemaType], xsd_types[name]) except KeyError: # If builtin type element is missing create a dummy element. Necessary for the # meta-schema XMLSchema.xsd of XSD 1.1, that not includes builtins declarations. elem = etree_element(XSD_SIMPLE_TYPE, name=name, id=name) else: elem, schema = value if schema is not meta_schema: raise XMLSchemaValueError("loaded entry schema is not the meta-schema!") base_type: Union[None, BaseXsdType, Tuple[ElementType, SchemaType]] if 'base_type' in item: base_type = item['base_type'] = xsd_types[item['base_type']] else: base_type = None facets = item.pop('facets', None) builtin_type: XsdAtomicBuiltin = atomic_builtin_class(elem, meta_schema, **item) if facets: built_facets = builtin_type.facets for e in facets: try: cls: Any = facets_map[e.tag] except AttributeError: built_facets[None] = e else: built_facets[e.tag] = cls(e, meta_schema, builtin_type, base_type) builtin_type.facets = built_facets xsd_types[name] = builtin_type ������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/complex_types.py����������������������������������������������0000664�0000000�0000000�00000132750�14211403446�0023157�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from collections.abc import MutableSequence from typing import cast, Any, Callable, Iterator, List, Optional, Tuple, Union from ..exceptions import XMLSchemaValueError from ..names import XSD_GROUP, XSD_ATTRIBUTE_GROUP, XSD_SEQUENCE, XSD_OVERRIDE, \ XSD_ALL, XSD_CHOICE, XSD_ANY_ATTRIBUTE, XSD_ATTRIBUTE, XSD_COMPLEX_CONTENT, \ XSD_RESTRICTION, XSD_COMPLEX_TYPE, XSD_EXTENSION, XSD_ANY_TYPE, XSD_ASSERT, \ XSD_UNTYPED_ATOMIC, XSD_SIMPLE_CONTENT, XSD_OPEN_CONTENT, XSD_ANNOTATION from ..aliases import ElementType, NamespacesType, SchemaType, ComponentClassType, \ DecodeType, IterDecodeType, IterEncodeType, BaseXsdType, AtomicValueType, \ ExtraValidatorType from ..helpers import get_prefixed_qname, get_qname, local_name from .. import dataobjects from .exceptions import XMLSchemaDecodeError from .helpers import get_xsd_derivation_attribute from .xsdbase import XSD_TYPE_DERIVATIONS, XsdComponent, XsdType, ValidationMixin from .attributes import XsdAttributeGroup from .assertions import XsdAssert from .simple_types import FacetsValueType, XsdSimpleType, XsdUnion from .groups import XsdGroup from .wildcards import XsdOpenContent, XsdDefaultOpenContent XSD_MODEL_GROUP_TAGS = {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE} class XsdComplexType(XsdType, ValidationMixin[Union[ElementType, str, bytes], Any]): """ Class for XSD 1.0 *complexType* definitions. :var attributes: the attribute group related with the complexType. :var content: the content of the complexType can be a model group or a simple type. :var mixed: if `True` the complex type has mixed content. .. <complexType abstract = boolean : false block = (#all | List of (extension | restriction)) final = (#all | List of (extension | restriction)) id = ID mixed = boolean : false name = NCName {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))) </complexType> """ attributes: XsdAttributeGroup copy: Callable[['XsdComplexType'], 'XsdComplexType'] content: Union[XsdGroup, XsdSimpleType] = None # type: ignore[assignment] abstract: bool = False mixed: bool = False assertions: Union[Tuple[()], List[XsdAssert]] = () open_content: Optional[XsdOpenContent] = None _block: Optional[str] = None _ADMITTED_TAGS = {XSD_COMPLEX_TYPE, XSD_RESTRICTION} _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE} @staticmethod def normalize(text: Union[str, bytes]) -> str: return text.decode('utf-8') if isinstance(text, bytes) else text def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent] = None, name: Optional[str] = None, **kwargs: Any) -> None: if kwargs: if 'content' in kwargs: self.content = kwargs['content'] if 'attributes' in kwargs: self.attributes = kwargs['attributes'] if 'mixed' in kwargs: self.mixed = kwargs['mixed'] if 'block' in kwargs: self._block = kwargs['block'] if 'final' in kwargs: self._final = kwargs['final'] super(XsdComplexType, self).__init__(elem, schema, parent, name) assert self.content is not None def __repr__(self) -> str: if self.name is not None: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) elif not hasattr(self, 'content') or not hasattr(self, 'attributes'): return '%s(id=%r)' % (self.__class__.__name__, id(self)) else: return '%s(content=%r, attributes=%r)' % ( self.__class__.__name__, self.content_type_label, [a if a.name is None else a.prefixed_name for a in self.attributes.values()] ) def _parse(self) -> None: if self.elem.tag == XSD_RESTRICTION: return # a local restriction is already parsed by the caller if 'abstract' in self.elem.attrib: if self.elem.attrib['abstract'].strip() in {'true', '1'}: self.abstract = True if 'block' in self.elem.attrib: try: self._block = get_xsd_derivation_attribute(self.elem, 'block', XSD_TYPE_DERIVATIONS) except ValueError as err: self.parse_error(err) if 'final' in self.elem.attrib: try: self._final = get_xsd_derivation_attribute(self.elem, 'final', XSD_TYPE_DERIVATIONS) except ValueError as err: self.parse_error(err) if 'mixed' in self.elem.attrib: if self.elem.attrib['mixed'].strip() in {'true', '1'}: self.mixed = True try: self.name = get_qname(self.target_namespace, self.elem.attrib['name']) except KeyError: self.name = None if self.parent is None: self.parse_error("missing attribute 'name' in a global complexType") self.name = 'nameless_%s' % str(id(self)) else: if self.parent is not None: self.parse_error("attribute 'name' not allowed for a local complexType") self.name = None content_elem = self._parse_child_component(self.elem, strict=False) if content_elem is None or content_elem.tag in self._CONTENT_TAIL_TAGS: self.content = self.schema.create_empty_content_group(self) self._parse_content_tail(self.elem) default_open_content = self.default_open_content if default_open_content is not None and \ (self.mixed or self.content or default_open_content.applies_to_empty): self.open_content = default_open_content elif content_elem.tag in {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: self.content = self.schema.xsd_group_class(content_elem, self.schema, self) default_open_content = self.default_open_content if default_open_content is not None and \ (self.mixed or self.content or default_open_content.applies_to_empty): self.open_content = default_open_content self._parse_content_tail(self.elem) elif content_elem.tag == XSD_SIMPLE_CONTENT: if 'mixed' in content_elem.attrib: self.parse_error("'mixed' attribute not allowed with simpleContent", content_elem) derivation_elem = self._parse_derivation_elem(content_elem) if derivation_elem is None: return self.base_type = base_type = self._parse_base_type(derivation_elem) if derivation_elem.tag == XSD_RESTRICTION: self._parse_simple_content_restriction(derivation_elem, base_type) else: self._parse_simple_content_extension(derivation_elem, base_type) if content_elem is not self.elem[-1]: k = 2 if content_elem is not self.elem[0] else 1 self.parse_error( "unexpected tag %r after simpleContent declaration:" % self.elem[k].tag ) elif content_elem.tag == XSD_COMPLEX_CONTENT: # # complexType with complexContent restriction/extension if 'mixed' in content_elem.attrib: mixed = content_elem.attrib['mixed'] in ('true', '1') if mixed is not self.mixed: self.mixed = mixed if 'mixed' in self.elem.attrib and self.xsd_version == '1.1': self.parse_error("value of 'mixed' attribute in complexType " "and complexContent must be same") derivation_elem = self._parse_derivation_elem(content_elem) if derivation_elem is None: return self.base_type = self._parse_base_type(derivation_elem, complex_content=True) if self.base_type is self and self.redefine is not None: self.base_type = self.redefine self.open_content = None if derivation_elem.tag == XSD_RESTRICTION: self._parse_complex_content_restriction(derivation_elem, self.base_type) else: self._parse_complex_content_extension(derivation_elem, self.base_type) if content_elem is not self.elem[-1]: k = 2 if content_elem is not self.elem[0] else 1 self.parse_error( "unexpected tag %r after complexContent declaration:" % self.elem[k].tag ) elif content_elem.tag == XSD_OPEN_CONTENT and self.xsd_version > '1.0': self.open_content = XsdOpenContent(content_elem, self.schema, self) if content_elem is self.elem[-1]: self.content = self.schema.create_empty_content_group(self) else: for index, child in enumerate(self.elem): if content_elem is not child: continue elif self.elem[index + 1].tag in {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: self.content = self.schema.xsd_group_class( self.elem[index + 1], self.schema, self ) else: self.content = self.schema.create_empty_content_group(self) break self._parse_content_tail(self.elem) else: if self.schema.validation == 'skip': # Also generated by meta-schema validation for 'lax' and 'strict' modes self.parse_error( "unexpected tag %r for complexType content:" % content_elem.tag ) self.content = self.schema.create_any_content_group(self) self.attributes = self.schema.create_any_attribute_group(self) if self.redefine is None: if self.base_type is not None and self.base_type.name == self.name: self.parse_error("wrong definition with self-reference") elif self.base_type is None or self.base_type.name != self.name: self.parse_error("wrong redefinition without self-reference") def _parse_content_tail(self, elem: ElementType, **kwargs: Any) -> None: self.attributes = self.schema.xsd_attribute_group_class( elem, self.schema, self, **kwargs ) def _parse_derivation_elem(self, elem: ElementType) -> Optional[ElementType]: derivation_elem = self._parse_child_component(elem) if derivation_elem is None or derivation_elem.tag not in {XSD_RESTRICTION, XSD_EXTENSION}: self.parse_error("restriction or extension tag expected", derivation_elem) self.content = self.schema.create_any_content_group(self) self.attributes = self.schema.create_any_attribute_group(self) return None if self.derivation is not None and self.redefine is None: raise XMLSchemaValueError("{!r} is expected to have a redefined/" "overridden component".format(self)) self.derivation = local_name(derivation_elem.tag) if self.base_type is not None and self.derivation in self.base_type.final: self.parse_error(f"{self.derivation!r} derivation not allowed for {self!r}") return derivation_elem def _parse_base_type(self, elem: ElementType, complex_content: bool = False) \ -> Union[XsdSimpleType, 'XsdComplexType']: try: base_qname = self.schema.resolve_qname(elem.attrib['base']) except (KeyError, ValueError, RuntimeError) as err: if 'base' not in elem.attrib: self.parse_error("'base' attribute required", elem) else: self.parse_error(err, elem) return self.any_type try: base_type = self.maps.lookup_type(base_qname) except KeyError: self.parse_error("missing base type %r" % base_qname, elem) if complex_content: return self.any_type else: return self.any_simple_type else: if isinstance(base_type, tuple): self.parse_error("circularity definition found between %r " "and %r" % (self, base_qname), elem) return self.any_type elif complex_content and base_type.is_simple(): self.parse_error("a complexType ancestor required: %r" % base_type, elem) return self.any_type if base_type.final and elem.tag.rsplit('}', 1)[-1] in base_type.final: msg = "derivation by %r blocked by attribute 'final' in base type" self.parse_error(msg % elem.tag.rsplit('}', 1)[-1]) return base_type def _parse_simple_content_restriction(self, elem: ElementType, base_type: Any) -> None: # simpleContent restriction: the base type must be a complexType with a simple # content or a complex content with a mixed and emptiable content. if base_type.is_simple(): self.parse_error("a complexType ancestor required: %r" % base_type, elem) self.content = self.schema.create_any_content_group(self) self._parse_content_tail(elem) else: if base_type.is_empty(): self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) if not self.is_empty(): self.parse_error("a not empty simpleContent cannot restrict " "an empty content type", elem) self.content = self.schema.create_any_content_group(self) elif base_type.has_simple_content(): self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) if not self.content.is_derived(base_type.content, 'restriction'): self.parse_error("content type is not a restriction of base content", elem) elif base_type.mixed and base_type.is_emptiable(): self.content = self.schema.xsd_atomic_restriction_class(elem, self.schema, self) else: self.parse_error("with simpleContent cannot restrict an " "element-only content type", elem) self.content = self.schema.create_any_content_group(self) self._parse_content_tail(elem, derivation='restriction', base_attributes=base_type.attributes) def _parse_simple_content_extension(self, elem: ElementType, base_type: Any) -> None: # simpleContent extension: the base type must be a simpleType or a complexType # with simple content. child = self._parse_child_component(elem, strict=False) if child is not None and child.tag not in self._CONTENT_TAIL_TAGS: self.parse_error('unexpected tag %r' % child.tag, child) if base_type.is_simple(): self.content = base_type self._parse_content_tail(elem) else: if base_type.has_simple_content(): self.content = base_type.content else: self.parse_error("base type %r has not simple content." % base_type, elem) self.content = self.schema.create_any_content_group(self) self._parse_content_tail(elem, derivation='extension', base_attributes=base_type.attributes) def _parse_complex_content_restriction(self, elem: ElementType, base_type: Any) -> None: if 'restriction' in base_type.final: self.parse_error("the base type is not derivable by restriction") if base_type.is_simple() or base_type.has_simple_content(): self.parse_error("base %r is simple or has a simple content." % base_type, elem) base_type = self.any_type # complexContent restriction: the base type must be a complexType with a complex content. for child in elem: if child.tag == XSD_OPEN_CONTENT and self.xsd_version > '1.0': self.open_content = XsdOpenContent(child, self.schema, self) continue elif child.tag in XSD_MODEL_GROUP_TAGS: content = self.schema.xsd_group_class(child, self.schema, self) if not base_type.content.admits_restriction(content.model): self.parse_error( "restriction of an xs:{} with more than one particle with xs:{} is " "forbidden".format(base_type.content.model, content.model) ) break else: content = self.schema.create_empty_content_group( self, base_type.content.model ) content.restriction = base_type.content if base_type.is_element_only() and content.mixed: self.parse_error( "derived a mixed content from a base type that has element-only content.", elem ) elif base_type.is_empty() and not content.is_empty(): self.parse_error( "derived an empty content from base type that has not empty content.", elem ) if self.open_content is None: default_open_content = self.default_open_content if default_open_content is not None and \ (self.mixed or content or default_open_content.applies_to_empty): self.open_content = default_open_content if self.open_content and content and \ not self.open_content.is_restriction(base_type.open_content): msg = "{!r} is not a restriction of the base type {!r}" self.parse_error(msg.format(self.open_content, base_type.open_content)) self.content = content self._parse_content_tail(elem, derivation='restriction', base_attributes=base_type.attributes) def _parse_complex_content_extension(self, elem: ElementType, base_type: Any) -> None: if 'extension' in base_type.final: self.parse_error("the base type is not derivable by extension") group_elem: Optional[ElementType] for group_elem in elem: if group_elem.tag != XSD_ANNOTATION and not callable(group_elem.tag): break else: group_elem = None if base_type.is_empty(): if not base_type.mixed: # Empty element-only model extension: don't create a nested group. if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: self.content = self.schema.xsd_group_class( group_elem, self.schema, self ) elif base_type.is_simple() or base_type.has_simple_content(): self.content = self.schema.create_empty_content_group(self) else: self.content = self.schema.create_empty_content_group( parent=self, elem=base_type.content.elem ) elif base_type.mixed: # Empty mixed model extension self.content = self.schema.create_empty_content_group(self) self.content.append(self.schema.create_empty_content_group(self.content)) if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: group = self.schema.xsd_group_class( group_elem, self.schema, self.content ) if not self.mixed: self.parse_error("base has a different content type (mixed=%r) and the " "extension group is not empty." % base_type.mixed, elem) else: group = self.schema.create_empty_content_group(self) self.content.append(group) self.content.elem.append(base_type.content.elem) self.content.elem.append(group.elem) elif group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: # Derivation from a simple content is forbidden if base type is not empty. if base_type.is_simple() or base_type.has_simple_content(): self.parse_error("base %r is simple or has a simple content." % base_type, elem) base_type = self.any_type group = self.schema.xsd_group_class(group_elem, self.schema, self) if group.model == 'all': self.parse_error("cannot extend a complex content with xs:all") if base_type.content.model == 'all' and group.model == 'sequence': self.parse_error("xs:sequence cannot extend xs:all") content = self.schema.create_empty_content_group(self) content.append(base_type.content) content.append(group) content.elem.append(base_type.content.elem) content.elem.append(group.elem) if base_type.content.model == 'all' and base_type.content and group: self.parse_error( "XSD 1.0 does not allow extension of a not empty 'all' model group" ) if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE: self.parse_error("base has a different content type (mixed=%r) and the " "extension group is not empty" % base_type.mixed, elem) self.content = content elif base_type.is_simple(): self.content = base_type elif base_type.has_simple_content(): self.content = base_type.content else: self.content = self.schema.create_empty_content_group(self) self.content.append(base_type.content) self.content.elem.append(base_type.content.elem) if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE and self.mixed: self.parse_error( "extended type has a mixed content but the base is element-only", elem ) self._parse_content_tail(elem, derivation='extension', base_attributes=base_type.attributes) @property def default_open_content(self) -> Optional[XsdDefaultOpenContent]: return None @property def block(self) -> str: return self.schema.block_default if self._block is None else self._block @property def built(self) -> bool: return self.content.parent is not None or self.content.built @property def validation_attempted(self) -> str: return 'full' if self.built else self.content.validation_attempted @property def simple_type(self) -> Optional[XsdSimpleType]: return self.content if isinstance(self.content, XsdSimpleType) else None @property def model_group(self) -> Optional[XsdGroup]: return self.content if isinstance(self.content, XsdGroup) else None @property def content_type(self) -> Union[XsdGroup, XsdSimpleType]: """Property that returns the attribute *content*, for backward compatibility.""" import warnings warnings.warn("'content_type' attribute has been replaced by 'content' " "and will be removed in version 2.0", DeprecationWarning, stacklevel=2) return self.content @property def content_type_label(self) -> str: if self.is_empty(): return 'empty' elif isinstance(self.content, XsdSimpleType): return 'simple' elif self.mixed: return 'mixed' else: return 'element-only' @property def sequence_type(self) -> str: if self.is_empty(): return 'empty-sequence()' elif not self.has_simple_content(): st = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces) else: try: st = self.content.primitive_type.prefixed_name # type: ignore[union-attr] except AttributeError: st = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces) else: if st is None: st = 'item()' return f"{st}{'*' if self.is_emptiable() else '+'}" @staticmethod def is_simple() -> bool: return False @staticmethod def is_complex() -> bool: return True def is_empty(self) -> bool: if self.open_content and self.open_content.mode != 'none': return False return self.content.is_empty() def is_emptiable(self) -> bool: return self.content.is_emptiable() def has_simple_content(self) -> bool: if not isinstance(self.content, XsdGroup): return not self.content.is_empty() elif self.content or self.content.mixed or self.base_type is None: return False else: return self.base_type.is_simple() or self.base_type.has_simple_content() def has_complex_content(self) -> bool: if not isinstance(self.content, XsdGroup): return False elif self.open_content and self.open_content.mode != 'none': return True return not self.content.is_empty() def has_mixed_content(self) -> bool: if not isinstance(self.content, XsdGroup): return False elif self.content.is_empty(): return False else: return self.content.mixed def is_element_only(self) -> bool: if not isinstance(self.content, XsdGroup): return False elif self.content.is_empty(): return False else: return not self.content.mixed def is_list(self) -> bool: return isinstance(self.content, XsdSimpleType) and self.content.is_list() def validate(self, obj: Union[ElementType, str, bytes], use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> None: kwargs: Any = { 'use_defaults': use_defaults, 'namespaces': namespaces, 'max_depth': max_depth, 'extra_validator': extra_validator } if not isinstance(obj, (str, bytes)): super(XsdComplexType, self).validate(obj, **kwargs) elif isinstance(self.content, XsdSimpleType): self.content.validate(obj, **kwargs) elif not self.mixed and self.base_type is not None: self.base_type.validate(obj, **kwargs) def is_valid(self, obj: Union[ElementType, str, bytes], use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> bool: kwargs: Any = { 'use_defaults': use_defaults, 'namespaces': namespaces, 'max_depth': max_depth, 'extra_validator': extra_validator } if not isinstance(obj, (str, bytes)): return super(XsdComplexType, self).is_valid(obj, **kwargs) elif isinstance(self.content, XsdSimpleType): return self.content.is_valid(obj, **kwargs) else: return self.mixed or self.base_type is not None and \ self.base_type.is_valid(obj, **kwargs) def is_derived(self, other: Union[BaseXsdType, Tuple[ElementType, SchemaType]], derivation: Optional[str] = None) -> bool: if derivation and derivation == self.derivation: derivation = None # derivation mode checked if self is other: return derivation is None elif isinstance(other, tuple): other[1].parse_error(f"global type {other[0].tag!r} is not built") return False elif other.name == XSD_ANY_TYPE: return True elif self.base_type is other: return derivation is None # or self.base_type.derivation == derivation elif isinstance(other, XsdUnion): return any(self.is_derived(m, derivation) for m in other.member_types) elif self.base_type is None: if not self.has_simple_content(): return False return isinstance(self.content, XsdSimpleType) and \ self.content.is_derived(other, derivation) elif self.has_simple_content(): return isinstance(self.content, XsdSimpleType) and \ self.content.is_derived(other, derivation) or \ self.base_type.is_derived(other, derivation) else: return self.base_type.is_derived(other, derivation) def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self if self.attributes and self.attributes.parent is not None: yield from self.attributes.iter_components(xsd_classes) if self.content.parent is not None: yield from self.content.iter_components(xsd_classes) if self.base_type is not None and self.base_type.parent is not None: yield from self.base_type.iter_components(xsd_classes) for obj in filter(lambda x: x.base_type is self, self.assertions): if xsd_classes is None or isinstance(obj, xsd_classes): yield obj def get_facet(self, tag: str) -> Optional[FacetsValueType]: if isinstance(self.content, XsdSimpleType): return self.content.get_facet(tag) return None def admit_simple_restriction(self) -> bool: if 'restriction' in self.final: return False else: return self.has_simple_content() or self.mixed and self.is_emptiable() def has_restriction(self) -> bool: return self.derivation == 'restriction' def has_extension(self) -> bool: return self.derivation == 'extension' def text_decode(self, text: str) -> Optional[AtomicValueType]: if isinstance(self.content, XsdSimpleType): return cast(Optional[AtomicValueType], self.content.decode(text, 'skip')) else: return text def decode(self, obj: Union[ElementType, str, bytes], *args: Any, **kwargs: Any) \ -> DecodeType[Any]: if not isinstance(obj, (str, bytes)): return super(XsdComplexType, self).decode(obj, *args, **kwargs) elif isinstance(self.content, XsdSimpleType): return self.content.decode(obj, *args, **kwargs) else: raise XMLSchemaDecodeError( self, obj, str, "cannot decode %r data with %r" % (obj, self) ) def iter_decode(self, obj: Union[ElementType, str, bytes], validation: str = 'lax', **kwargs: Any) -> IterDecodeType[Any]: """ Decodes an Element instance using a dummy XSD element. Typically used for decoding with xs:anyType when an XSD element is not available. Also decodes strings if the type has a simple content. :param obj: the XML data that has to be decoded. :param validation: the validation mode. Can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the decoding process. :return: yields a decoded object, eventually preceded by a sequence of \ validation or decoding errors. """ if not isinstance(obj, (str, bytes)): xsd_element = self.schema.create_element(obj.tag, parent=self, form='unqualified') xsd_element.type = self yield from xsd_element.iter_decode(obj, validation, **kwargs) elif isinstance(self.content, XsdSimpleType): yield from self.content.iter_decode(obj, validation, **kwargs) else: raise XMLSchemaDecodeError( self, obj, str, "cannot decode %r data with %r" % (obj, self) ) def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[ElementType]: """ Encode XML data. A dummy element is created for the type and it's used for encode data. Typically used for encoding with xs:anyType when an XSD element is not available. :param obj: decoded XML data. :param validation: the validation mode: can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the encoding process. :return: yields an Element, eventually preceded by a sequence of \ validation or encoding errors. """ try: name, value = obj except ValueError: name = obj.name value = obj xsd_element = self.schema.create_element(name, parent=self, form='unqualified') xsd_element.type = self if isinstance(value, MutableSequence) and not isinstance(value, dataobjects.DataElement): try: results = [x for item in value for x in xsd_element.iter_encode( item, validation, **kwargs )] except XMLSchemaValueError: pass else: yield from results return yield from xsd_element.iter_encode(value, validation, **kwargs) class Xsd11ComplexType(XsdComplexType): """ Class for XSD 1.1 *complexType* definitions. .. <complexType abstract = boolean : false block = (#all | List of (extension | restriction)) final = (#all | List of (extension | restriction)) id = ID mixed = boolean name = NCName defaultAttributesApply = boolean : true {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleContent | complexContent | (openContent?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?), assert*))) </complexType> """ default_attributes_apply = True _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE_GROUP, XSD_ATTRIBUTE, XSD_ANY_ATTRIBUTE, XSD_ASSERT} @property def default_attributes(self) -> Optional[XsdAttributeGroup]: if self.redefine is not None: default_attributes = self.schema.default_attributes else: for child in self.schema.root: if child.tag == XSD_OVERRIDE and self.elem in child: schema = self.schema.includes[child.attrib['schemaLocation']] if schema.override is self.schema: default_attributes = schema.default_attributes break else: default_attributes = self.schema.default_attributes if isinstance(default_attributes, str): return None return default_attributes @property def default_open_content(self) -> Optional[XsdDefaultOpenContent]: if self.parent is not None: return self.schema.default_open_content for child in self.schema.root: if child.tag == XSD_OVERRIDE and self.elem in child: schema = self.schema.includes[child.attrib['schemaLocation']] if schema.override is self.schema: return schema.default_open_content else: return self.schema.default_open_content def _parse(self) -> None: super(Xsd11ComplexType, self)._parse() if self.base_type and self.base_type.base_type is self.any_simple_type and \ self.base_type.derivation == 'extension' and not self.attributes: # Derivation from xs:anySimpleType with missing variety. # See: http://www.w3.org/TR/xmlschema11-1/#Simple_Type_Definition_details msg = "the simple content of {!r} is not a valid simple type in XSD 1.1" self.parse_error(msg.format(self.base_type)) # Add open content to a complex content type if isinstance(self.content, XsdGroup): if self.open_content is None: if self.content.interleave is not None or self.content.suffix is not None: self.parse_error("openContent mismatch between type and model group") elif self.open_content.mode == 'interleave': self.content.interleave = self.content.suffix \ = self.open_content.any_element elif self.open_content.mode == 'suffix': self.content.suffix = self.open_content.any_element # Add inheritable attributes if isinstance(self.base_type, XsdComplexType): for name, attr in self.base_type.attributes.items(): if attr.inheritable: if name not in self.attributes: self.attributes[name] = attr elif not self.attributes[name].inheritable: self.parse_error("attribute %r must be inheritable") if 'defaultAttributesApply' not in self.elem.attrib: self.default_attributes_apply = True elif self.elem.attrib['defaultAttributesApply'].strip() in {'false', '0'}: self.default_attributes_apply = False else: self.default_attributes_apply = True # Add default attributes if self.default_attributes_apply and \ isinstance(self.default_attributes, XsdAttributeGroup): if self.redefine is None: for k in self.default_attributes: if k in self.attributes: self.parse_error(f"default attribute {k!r} is already " f"declared in the complex type") self.attributes.update((k, v) for k, v in self.default_attributes.items()) def _parse_complex_content_extension(self, elem: ElementType, base_type: Any) -> None: # Complex content extension with simple base is forbidden XSD 1.1. # For the detailed rule refer to XSD 1.1 documentation: # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#sec-cos-ct-extends if base_type.is_simple() or base_type.has_simple_content(): self.parse_error("base %r is simple or has a simple content." % base_type, elem) base_type = self.any_type if 'extension' in base_type.final: self.parse_error("the base type is not derivable by extension") # Parse openContent group_elem: Any for group_elem in elem: if group_elem.tag == XSD_ANNOTATION or callable(group_elem.tag): continue elif group_elem.tag != XSD_OPEN_CONTENT: break self.open_content = XsdOpenContent(group_elem, self.schema, self) try: any_element = base_type.open_content.any_element self.open_content.any_element.union(any_element) except AttributeError: pass else: group_elem = None if not base_type.content: if not base_type.mixed: # Empty element-only model extension: don't create a nested sequence group. if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: self.content = self.schema.xsd_group_class( group_elem, self.schema, self ) elif base_type.content.max_occurs is None: self.content = self.schema.create_empty_content_group( parent=self, model=base_type.content.model, minOccurs=str(base_type.content.min_occurs), maxOccurs='unbounded', ) else: self.content = self.schema.create_empty_content_group( parent=self, model=base_type.content.model, minOccurs=str(base_type.content.min_occurs), maxOccurs=str(base_type.content.max_occurs), ) elif base_type.mixed: # Empty mixed model extension self.content = self.schema.create_empty_content_group(self) self.content.append(self.schema.create_empty_content_group(self.content)) if group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: group = self.schema.xsd_group_class( group_elem, self.schema, self.content ) if not self.mixed: self.parse_error("base has a different content type (mixed=%r) and the " "extension group is not empty." % base_type.mixed, elem) if group.model == 'all': self.parse_error("cannot extend an empty mixed content with an xs:all") else: group = self.schema.create_empty_content_group(self) self.content.append(group) self.content.elem.append(base_type.content.elem) self.content.elem.append(group.elem) elif group_elem is not None and group_elem.tag in XSD_MODEL_GROUP_TAGS: group = self.schema.xsd_group_class(group_elem, self.schema, self) if base_type.content.model != 'all': content = self.schema.create_empty_content_group(self) content.append(base_type.content) content.elem.append(base_type.content.elem) if group.model == 'all': msg = "xs:all cannot extend a not empty xs:%s" self.parse_error(msg % base_type.content.model) else: content.append(group) content.elem.append(group.elem) else: content = self.schema.create_empty_content_group( self, model='all', minOccurs=str(base_type.content.min_occurs) ) content.extend(base_type.content) content.elem.extend(base_type.content.elem) if not group: pass elif group.model != 'all': self.parse_error( "cannot extend a not empty 'all' model group with a different model" ) elif base_type.content.min_occurs != group.min_occurs: self.parse_error("when extend an xs:all group minOccurs must be the same") elif base_type.mixed and not base_type.content: self.parse_error("cannot extend an xs:all group with mixed empty content") else: content.extend(group) content.elem.extend(group.elem) if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE: self.parse_error("base has a different content type (mixed=%r) and the " "extension group is not empty." % base_type.mixed, elem) self.content = content elif base_type.is_simple(): self.content = base_type elif base_type.has_simple_content(): self.content = base_type.content else: self.content = self.schema.create_empty_content_group(self) self.content.append(base_type.content) self.content.elem.append(base_type.content.elem) if base_type.mixed != self.mixed and base_type.name != XSD_ANY_TYPE and self.mixed: self.parse_error( "extended type has a mixed content but the base is element-only", elem ) if self.open_content is None: default_open_content = self.default_open_content if default_open_content is not None and \ (self.mixed or self.content or default_open_content.applies_to_empty): self.open_content = default_open_content elif base_type.open_content is not None: self.open_content = base_type.open_content if base_type.open_content is not None and \ self.open_content is not None and \ self.open_content is not base_type.open_content: if self.open_content.mode == 'none': self.open_content = base_type.open_content elif not base_type.open_content.is_restriction(self.open_content): msg = "{!r} is not an extension of the base type {!r}" self.parse_error(msg.format(self.open_content, base_type.open_content)) self._parse_content_tail(elem, derivation='extension', base_attributes=base_type.attributes) def _parse_content_tail(self, elem: ElementType, **kwargs: Any) -> None: self.attributes = self.schema.xsd_attribute_group_class( elem, self.schema, self, **kwargs ) self.assertions = [XsdAssert(e, self.schema, self, self) for e in elem if e.tag == XSD_ASSERT] if isinstance(self.base_type, XsdComplexType): self.assertions.extend( XsdAssert(assertion.elem, self.schema, self, self) for assertion in self.base_type.assertions ) ������������������������xmlschema-1.10.0/xmlschema/validators/elements.py���������������������������������������������������0000664�0000000�0000000�00000172052�14211403446�0022077�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for XML Schema elements, complex types and model groups. """ import warnings from decimal import Decimal from types import GeneratorType from typing import TYPE_CHECKING, cast, Any, Dict, Iterator, List, Optional, Tuple, Type, Union from elementpath import XPath2Parser, ElementPathError, XPathContext, XPathToken from elementpath.datatypes import AbstractDateTime, Duration, AbstractBinary from ..exceptions import XMLSchemaTypeError, XMLSchemaValueError from ..names import XSD_COMPLEX_TYPE, XSD_SIMPLE_TYPE, XSD_ALTERNATIVE, \ XSD_ELEMENT, XSD_ANY_TYPE, XSD_UNIQUE, XSD_KEY, XSD_KEYREF, XSI_NIL, \ XSI_TYPE, XSD_ERROR, XSD_NOTATION_TYPE from ..etree import ElementData, etree_element from ..aliases import ElementType, SchemaType, BaseXsdType, SchemaElementType, \ ModelParticleType, ComponentClassType, AtomicValueType, DecodeType, \ IterDecodeType, IterEncodeType from ..helpers import get_qname, get_namespace, etree_iter_location_hints, \ raw_xml_encode, strictly_equal from .. import dataobjects from ..converters import XMLSchemaConverter from ..xpath import XMLSchemaProtocol, ElementProtocol, XMLSchemaProxy, \ ElementPathMixin, XPathElement from .exceptions import XMLSchemaValidationError, XMLSchemaTypeTableWarning from .helpers import get_xsd_derivation_attribute from .xsdbase import XSD_TYPE_DERIVATIONS, XSD_ELEMENT_DERIVATIONS, \ XsdComponent, ValidationMixin from .particles import ParticleMixin, OccursCalculator from .identities import IdentityXPathContext, XsdIdentity, XsdKey, XsdUnique, \ XsdKeyref, IdentityCounter, IdentityCounterType from .simple_types import XsdSimpleType from .attributes import XsdAttribute from .wildcards import XsdAnyElement if TYPE_CHECKING: from .attributes import XsdAttributeGroup from .groups import XsdGroup DataBindingType = Type['dataobjects.DataElement'] class XsdElement(XsdComponent, ParticleMixin, ElementPathMixin[SchemaElementType], ValidationMixin[ElementType, Any]): """ Class for XSD 1.0 *element* declarations. :ivar type: the XSD simpleType or complexType of the element. :ivar attributes: the group of the attributes associated with the element. .. <element abstract = boolean : false block = (#all | List of (extension | restriction | substitution)) default = string final = (#all | List of (extension | restriction)) fixed = string form = (qualified | unqualified) id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 name = NCName nillable = boolean : false ref = QName substitutionGroup = QName type = QName {any attributes with non-schema namespace . . .}> Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) </element> """ name: str local_name: str qualified_name: str prefixed_name: str parent: Optional['XsdGroup'] ref: Optional['XsdElement'] attributes: 'XsdAttributeGroup' type: BaseXsdType abstract = False nillable = False qualified = False form: Optional[str] = None default: Optional[str] = None fixed: Optional[str] = None substitution_group: Optional[str] = None identities: Dict[str, XsdIdentity] alternatives = () # type: Union[Tuple[()], List[XsdAlternative]] inheritable = () # type: Union[Tuple[()], Dict[str, XsdAttribute]] _ADMITTED_TAGS = {XSD_ELEMENT} _block: Optional[str] = None _final: Optional[str] = None _head_type = None _build = True binding: Optional[DataBindingType] = None def __init__(self, elem: etree_element, schema: SchemaType, parent: Optional[XsdComponent] = None, build: bool = True) -> None: if not build: self._build = False super(XsdElement, self).__init__(elem, schema, parent) def __repr__(self) -> str: return '%s(%s=%r, occurs=%r)' % ( self.__class__.__name__, 'name' if self.ref is None else 'ref', self.prefixed_name, list(self.occurs) ) def __setattr__(self, name: str, value: Any) -> None: if name == "type": if isinstance(value, XsdSimpleType): self.attributes = self.schema.create_empty_attribute_group(self) else: self.attributes = value.attributes super(XsdElement, self).__setattr__(name, value) def __iter__(self) -> Iterator[SchemaElementType]: if self.type.has_complex_content(): yield from self.type.content.iter_elements() # type: ignore[union-attr] def _parse(self) -> None: if not self._build: return self._parse_particle(self.elem) self._parse_attributes() if self.ref is None: self._parse_type() self._parse_constraints() if self.parent is None and 'substitutionGroup' in self.elem.attrib: self._parse_substitution_group(self.elem.attrib['substitutionGroup']) def _parse_attributes(self) -> None: attrib = self.elem.attrib if self._parse_reference(): try: xsd_element: XsdElement = self.maps.lookup_element(self.name) except KeyError: self.type = self.any_type self.parse_error('unknown element %r' % self.name) else: self.ref = xsd_element self.type = xsd_element.type self.abstract = xsd_element.abstract self.nillable = xsd_element.nillable self.qualified = xsd_element.qualified self.form = xsd_element.form self.default = xsd_element.default self.fixed = xsd_element.fixed self.substitution_group = xsd_element.substitution_group self.identities = xsd_element.identities self.alternatives = xsd_element.alternatives for attr_name in {'type', 'nillable', 'default', 'fixed', 'form', 'block', 'abstract', 'final', 'substitutionGroup'}: if attr_name in attrib: msg = "attribute {!r} is not allowed when element reference is used" self.parse_error(msg.format(attr_name)) return if 'form' in attrib: self.form = attrib['form'] if self.form == 'qualified': self.qualified = True elif self.schema.element_form_default == 'qualified': self.qualified = True try: if self.parent is None or self.qualified: self.name = get_qname(self.target_namespace, attrib['name']) else: self.name = attrib['name'] except KeyError: pass if 'abstract' in attrib: if self.parent is not None: self.parse_error("local scope elements cannot have abstract attribute") if attrib['abstract'].strip() in {'true', '1'}: self.abstract = True if 'block' in attrib: try: self._block = get_xsd_derivation_attribute( self.elem, 'block', XSD_ELEMENT_DERIVATIONS ) except ValueError as err: self.parse_error(err) if 'nillable' in attrib and attrib['nillable'].strip() in {'true', '1'}: self.nillable = True if self.parent is None: if 'final' in attrib: try: self._final = get_xsd_derivation_attribute( self.elem, 'final', XSD_TYPE_DERIVATIONS ) except ValueError as err: self.parse_error(err) for attr_name in {'ref', 'form', 'minOccurs', 'maxOccurs'}: if attr_name in attrib: msg = "attribute {!r} is not allowed in a global element declaration" self.parse_error(msg.format(attr_name)) else: for attr_name in {'final', 'substitutionGroup'}: if attr_name in attrib: msg = "attribute {!r} not allowed in a local element declaration" self.parse_error(msg.format(attr_name)) def _parse_type(self) -> None: type_name = self.elem.get('type') if type_name is not None: try: extended_name = self.schema.resolve_qname(type_name) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) self.type = self.any_type else: if extended_name == XSD_ANY_TYPE: self.type = self.any_type else: try: self.type = self.maps.lookup_type(extended_name) except KeyError: self.parse_error('unknown type {!r}'.format(type_name)) self.type = self.any_type finally: child = self._parse_child_component(self.elem, strict=False) if child is not None and child.tag in (XSD_COMPLEX_TYPE, XSD_SIMPLE_TYPE): self.parse_error("the attribute 'type' and a {} local declaration " "are mutually exclusive".format(child.tag.split('}')[-1])) else: child = self._parse_child_component(self.elem, strict=False) if child is None: self.type = self.any_type elif child.tag == XSD_COMPLEX_TYPE: self.type = self.schema.xsd_complex_type_class(child, self.schema, self) elif child.tag == XSD_SIMPLE_TYPE: self.type = self.schema.simple_type_factory(child, self.schema, self) else: self.type = self.any_type def _parse_constraints(self) -> None: # Value constraints if 'default' in self.elem.attrib: self.default = self.elem.attrib['default'] if 'fixed' in self.elem.attrib: self.parse_error("'default' and 'fixed' attributes are mutually exclusive") if not self.type.is_valid(self.default): msg = "'default' value {!r} is not compatible with element's type" self.parse_error(msg.format(self.default)) self.default = None elif self.xsd_version == '1.0' and self.type.is_key(): self.parse_error("xs:ID or a type derived from xs:ID " "cannot have a default value") elif 'fixed' in self.elem.attrib: self.fixed = self.elem.attrib['fixed'] if not self.type.is_valid(self.fixed): msg = "'fixed' value {!r} is not compatible with element's type" self.parse_error(msg.format(self.fixed)) self.fixed = None elif self.xsd_version == '1.0' and self.type.is_key(): self.parse_error("xs:ID or a type derived from xs:ID " "cannot have a fixed value") # Identity constraints self.identities = {} constraint: Union[XsdKey, XsdUnique, XsdKeyref] for child in self.elem: if child.tag == XSD_UNIQUE: constraint = self.schema.xsd_unique_class(child, self.schema, self) elif child.tag == XSD_KEY: constraint = self.schema.xsd_key_class(child, self.schema, self) elif child.tag == XSD_KEYREF: constraint = self.schema.xsd_keyref_class(child, self.schema, self) else: # Invalid tags already caught by validation against the meta-schema continue if constraint.ref: if constraint.name in self.identities: self.parse_error("duplicated identity constraint %r:" % constraint.name, child) self.identities[constraint.name] = constraint continue try: if child != self.maps.identities[constraint.name].elem: self.parse_error("duplicated identity constraint %r:" % constraint.name, child) except KeyError: self.maps.identities[constraint.name] = constraint finally: self.identities[constraint.name] = constraint def _parse_substitution_group(self, substitution_group: str) -> None: try: substitution_group_qname = self.schema.resolve_qname(substitution_group) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) return else: if substitution_group_qname[0] != '{': substitution_group_qname = get_qname( self.target_namespace, substitution_group_qname ) try: head_element = self.maps.lookup_element(substitution_group_qname) except KeyError: self.parse_error("unknown substitutionGroup %r" % substitution_group) return else: if isinstance(head_element, tuple): self.parse_error("circularity found for substitutionGroup %r" % substitution_group) return elif 'substitution' in head_element.block: return final = head_element.final if self.type == head_element.type: pass elif self.type.name == XSD_ANY_TYPE: if head_element.type.name != XSD_ANY_TYPE: # Use head element's type for validate content # ref: https://www.w3.org/TR/xmlschema-1/#cElement_Declarations self._head_type = head_element.type elif not self.type.is_derived(head_element.type): self.parse_error("%r type is not of the same or a derivation " "of the head element %r type." % (self, head_element)) elif final == '#all' or 'extension' in final and 'restriction' in final: self.parse_error("head element %r can't be substituted by an element " "that has a derivation of its type" % head_element) elif 'extension' in final and self.type.is_derived(head_element.type, 'extension'): self.parse_error("head element %r can't be substituted by an element " "that has an extension of its type" % head_element) elif 'restriction' in final and self.type.is_derived(head_element.type, 'restriction'): self.parse_error("head element %r can't be substituted by an element " "that has a restriction of its type" % head_element) try: self.maps.substitution_groups[substitution_group_qname].add(self) except KeyError: self.maps.substitution_groups[substitution_group_qname] = {self} finally: self.substitution_group = substitution_group_qname @property def xpath_proxy(self) -> XMLSchemaProxy: return XMLSchemaProxy( schema=cast(XMLSchemaProtocol, self.schema), base_element=cast(ElementProtocol, self) ) def build(self) -> None: if self._build: return self._build = True self._parse() @property def built(self) -> bool: return hasattr(self, 'type') and \ (self.type.parent is None or self.type.built) and \ all(c.built for c in self.identities.values()) @property def validation_attempted(self) -> str: if self.built: return 'full' elif self.type.validation_attempted == 'partial': return 'partial' elif any(c.validation_attempted == 'partial' for c in self.identities.values()): return 'partial' else: return 'none' @property def scope(self) -> str: """The scope of the element declaration that can be 'global' or 'local'.""" return 'global' if self.parent is None else 'local' @property def value_constraint(self) -> Optional[str]: """The fixed or the default value if either is defined, `None` otherwise.""" return self.fixed if self.fixed is not None else self.default @property def final(self) -> str: if self.ref is not None: return self.ref.final elif self._final is not None: return self._final return self.schema.final_default @property def block(self) -> str: if self.ref is not None: return self.ref.block elif self._block is not None: return self._block return self.schema.block_default def get_binding(self, *bases: Type[Any], replace_existing: bool = False, **attrs: Any) \ -> DataBindingType: """ Gets data object binding for XSD element, creating a new one if it doesn't exist. :param bases: base classes to use for creating the binding class. :param replace_existing: provide `True` to replace an existing binding class. :param attrs: attribute and method definitions for the binding class body. """ if self.binding is None or not replace_existing: if not bases: bases = (dataobjects.DataElement,) attrs['xsd_element'] = self class_name = '{}Binding'.format(self.local_name.title().replace('_', '')) self.binding = cast(DataBindingType, dataobjects.DataBindingMeta(class_name, bases, attrs)) return self.binding def get_attribute(self, name: str) -> Optional[XsdAttribute]: if name[0] != '{': name = get_qname(self.type.target_namespace, name) if not isinstance(self.type, XsdSimpleType): xsd_attribute = self.type.attributes[name] assert isinstance(xsd_attribute, XsdAttribute) return xsd_attribute return None def get_type(self, elem: Union[ElementType, ElementData], inherited: Optional[Dict[str, Any]] = None) -> BaseXsdType: return self._head_type or self.type def get_attributes(self, xsd_type: BaseXsdType) -> 'XsdAttributeGroup': if not isinstance(xsd_type, XsdSimpleType): return xsd_type.attributes elif xsd_type is self.type: return self.attributes else: return self.schema.create_empty_attribute_group(self) def get_path(self, ancestor: Optional[XsdComponent] = None, reverse: bool = False) -> Optional[str]: """ Returns the XPath expression of the element. The path is relative to the schema instance in which the element is contained or is relative to a specific ancestor passed as argument. In the latter case returns `None` if the argument is not an ancestor. :param ancestor: optional XSD component of the same schema, that maybe \ an ancestor of the element. :param reverse: if set to `True` returns the reverse path, from the element to ancestor. """ path: List[str] = [] xsd_component: Optional[XsdComponent] = self while xsd_component is not None: if xsd_component is ancestor: return '/'.join(reversed(path)) or '.' elif isinstance(xsd_component, XsdElement): path.append('..' if reverse else xsd_component.name) xsd_component = xsd_component.parent else: if ancestor is None: return '/'.join(reversed(path)) or '.' return None def iter_components(self, xsd_classes: Optional[ComponentClassType] = None) \ -> Iterator[XsdComponent]: if xsd_classes is None: yield self yield from self.identities.values() else: if isinstance(self, xsd_classes): yield self if issubclass(XsdIdentity, xsd_classes): yield from self.identities.values() if self.ref is None and self.type.parent is not None: yield from self.type.iter_components(xsd_classes) def iter_substitutes(self) -> Iterator['XsdElement']: if self.parent is None or self.ref is not None: for xsd_element in self.maps.substitution_groups.get(self.name, ()): if not xsd_element.abstract: yield xsd_element for e in xsd_element.iter_substitutes(): if not e.abstract: yield e def data_value(self, elem: ElementType) -> Optional[AtomicValueType]: """Returns the decoded data value of the provided element as XPath fn:data().""" text = elem.text if text is None: text = self.fixed if self.fixed is not None else self.default if text is None: return None return self.type.text_decode(text) def check_dynamic_context(self, elem: ElementType, **kwargs: Any) -> None: try: locations = kwargs['locations'] except KeyError: return schema: Optional[SchemaType] for ns, url in etree_iter_location_hints(elem): if ns not in locations: locations[ns] = url elif locations[ns] is None: reason = "schemaLocation declaration after namespace start" raise XMLSchemaValidationError(self, elem, reason) if ns == self.target_namespace: schema = self.schema.include_schema(url, self.schema.base_url) else: schema = self.schema.import_schema(ns, url, self.schema.base_url) if schema is None: reason = f"missing dynamic loaded schema from {url}" raise XMLSchemaValidationError(self, elem, reason) elif not schema.built: reason = "dynamic loaded schema change the assessment" raise XMLSchemaValidationError(self, elem, reason) if elem.attrib: for name in elem.attrib: if name[0] == '{': ns = get_namespace(name) if ns not in locations: locations[ns] = None if elem.tag[0] == '{': ns = get_namespace(elem.tag) if ns not in locations: locations[ns] = None def start_identities(self, identities: Dict[XsdIdentity, IdentityCounter]) -> None: """ Start tracking of XSD element's identities. :param identities: a dictionary containing the identities counters. """ for constraint in self.identities.values(): try: identities[constraint].clear() except KeyError: identities[constraint] = constraint.get_counter() def stop_identities(self, identities: Dict[XsdIdentity, IdentityCounter]) -> None: """ Stop tracking of XSD element's identities. :param identities: a dictionary containing the identities counters. """ for identity in self.identities.values(): try: identities[identity].enabled = False except KeyError: identities[identity] = identity.get_counter(enabled=False) def iter_decode(self, obj: ElementType, validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[Any]: """ Creates an iterator for decoding an Element instance. :param obj: the Element that has to be decoded. :param validation: the validation mode, can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the decoding process. :return: yields a decoded object, eventually preceded by a sequence of \ validation or decoding errors. """ if self.abstract: reason = "cannot use an abstract element for validation" yield self.validation_error(validation, reason, obj, **kwargs) try: namespaces = kwargs['namespaces'] except KeyError: namespaces = None try: level = kwargs['level'] except KeyError: level = kwargs['level'] = 0 try: identities = kwargs['identities'] except KeyError: identities = kwargs['identities'] = {} self.start_identities(identities) try: converter = kwargs['converter'] except KeyError: converter = kwargs['converter'] = self.schema.get_converter(**kwargs) else: if converter is not None and not isinstance(converter, XMLSchemaConverter): converter = kwargs['converter'] = self.schema.get_converter(**kwargs) try: pass # self.check_dynamic_context(elem, **kwargs) TODO: dynamic schema load except XMLSchemaValidationError as err: yield self.validation_error(validation, err, obj, **kwargs) inherited = kwargs.get('inherited') value = content = attributes = None nilled = False # Get the instance effective type xsd_type = self.get_type(obj, inherited) if XSI_TYPE in obj.attrib: type_name = obj.attrib[XSI_TYPE].strip() try: xsd_type = self.maps.get_instance_type(type_name, xsd_type, namespaces) except (KeyError, TypeError) as err: yield self.validation_error(validation, err, obj, **kwargs) else: if self.identities: xpath_element = XPathElement(self.name, xsd_type) for identity in self.identities.values(): if isinstance(identity.elements, tuple): continue # Skip unbuilt identities context = IdentityXPathContext( self.schema, item=xpath_element # type: ignore[arg-type] ) for e in identity.selector.token.select_results(context): if not isinstance(e, XsdElement): reason = "selector xpath expression can only select elements" yield self.validation_error(validation, reason, e, **kwargs) elif e not in identity.elements: identity.elements[e] = None if xsd_type.is_blocked(self): reason = "usage of %r is blocked" % xsd_type yield self.validation_error(validation, reason, obj, **kwargs) if xsd_type.abstract: yield self.validation_error(validation, "%r is abstract", obj, **kwargs) if xsd_type.is_complex() and self.xsd_version == '1.1': kwargs['id_list'] = [] # Track XSD 1.1 multiple xs:ID attributes/children content_decoder = xsd_type if isinstance(xsd_type, XsdSimpleType) else xsd_type.content # Decode attributes attribute_group = self.get_attributes(xsd_type) result: Any for result in attribute_group.iter_decode(obj.attrib, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield self.validation_error(validation, result, obj, **kwargs) else: attributes = result if self.inheritable and any(name in self.inheritable for name in obj.attrib): if inherited: inherited = inherited.copy() inherited.update((k, v) for k, v in obj.attrib.items() if k in self.inheritable) else: inherited = {k: v for k, v in obj.attrib.items() if k in self.inheritable} kwargs['inherited'] = inherited # Checks the xsi:nil attribute of the instance if XSI_NIL in obj.attrib: xsi_nil = obj.attrib[XSI_NIL].strip() if not self.nillable: reason = "element is not nillable." yield self.validation_error(validation, reason, obj, **kwargs) elif xsi_nil not in {'0', '1', 'false', 'true'}: reason = "xsi:nil attribute must have a boolean value." yield self.validation_error(validation, reason, obj, **kwargs) elif xsi_nil in ('0', 'false'): pass elif self.fixed is not None: reason = "xsi:nil='true' but the element has a fixed value." yield self.validation_error(validation, reason, obj, **kwargs) elif obj.text is not None or len(obj): reason = "xsi:nil='true' but the element is not empty." yield self.validation_error(validation, reason, obj, **kwargs) else: nilled = True if xsd_type.is_empty() and obj.text and xsd_type.normalize(obj.text): reason = "character data is not allowed because content is empty" yield self.validation_error(validation, reason, obj, **kwargs) if nilled: pass elif not isinstance(content_decoder, XsdSimpleType): if not isinstance(xsd_type, XsdSimpleType): for assertion in xsd_type.assertions: for error in assertion(obj, **kwargs): yield self.validation_error(validation, error, **kwargs) for result in content_decoder.iter_decode(obj, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield self.validation_error(validation, result, obj, **kwargs) else: content = result if content and len(content) == 1 and content[0][0] == 1: value, content = content[0][1], None if self.fixed is not None and \ (len(obj) > 0 or value is not None and self.fixed != value): reason = "must have the fixed value %r" % self.fixed yield self.validation_error(validation, reason, obj, **kwargs) else: if len(obj): reason = "a simple content element can't have child elements." yield self.validation_error(validation, reason, obj, **kwargs) text = obj.text if self.fixed is not None: if text is None: text = self.fixed elif text == self.fixed: pass elif not strictly_equal(xsd_type.text_decode(text), xsd_type.text_decode(self.fixed)): reason = "must have the fixed value %r" % self.fixed yield self.validation_error(validation, reason, obj, **kwargs) elif not text and self.default is not None and kwargs.get('use_defaults'): text = self.default if not isinstance(xsd_type, XsdSimpleType): for assertion in xsd_type.assertions: for error in assertion(obj, value=text, **kwargs): yield self.validation_error(validation, error, **kwargs) if text and content_decoder.is_list(): value = text.split() else: value = text elif xsd_type.is_notation(): if xsd_type.name == XSD_NOTATION_TYPE: msg = "cannot validate against xs:NOTATION directly, " \ "only against a subtype with an enumeration facet" yield self.validation_error(validation, msg, text, **kwargs) elif not xsd_type.enumeration: msg = "missing enumeration facet in xs:NOTATION subtype" yield self.validation_error(validation, msg, text, **kwargs) if text is None: for result in content_decoder.iter_decode('', validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield self.validation_error(validation, result, obj, **kwargs) if 'filler' in kwargs: value = kwargs['filler'](self) else: for result in content_decoder.iter_decode(text, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield self.validation_error(validation, result, obj, **kwargs) elif result is None and 'filler' in kwargs: value = kwargs['filler'](self) else: value = result if 'value_hook' in kwargs: value = kwargs['value_hook'](value, xsd_type) elif isinstance(value, (int, float, list)) or value is None: pass elif isinstance(value, str): if value.startswith('{') and xsd_type.is_qname(): value = text elif isinstance(value, Decimal): try: value = kwargs['decimal_type'](value) except (KeyError, TypeError): pass elif isinstance(value, (AbstractDateTime, Duration)): if not kwargs.get('datetime_types'): value = str(value) if text is None else text.strip() elif isinstance(value, AbstractBinary): if not kwargs.get('binary_types'): value = str(value) if converter is not None: element_data = ElementData(obj.tag, value, content, attributes) yield converter.element_decode(element_data, self, xsd_type, level) elif not level: yield ElementData(obj.tag, value, None, attributes) if content is not None: del content # Collects fields values for identities that refer to this element. for identity, counter in identities.items(): if not counter.enabled or not identity.elements: continue elif self in identity.elements: xsd_element = self elif self.ref in identity.elements: xsd_element = self.ref else: continue try: xsd_fields: Optional[IdentityCounterType] if xsd_type is self.type: xsd_fields = identity.elements[xsd_element] if xsd_fields is None: xsd_fields = identity.get_fields(xsd_element) identity.elements[xsd_element] = xsd_fields else: xsd_element = cast(XsdElement, self.copy()) xsd_element.type = xsd_type xsd_fields = identity.get_fields(xsd_element) if all(x is None for x in xsd_fields): continue decoders = cast(Tuple[XsdAttribute, ...], xsd_fields) fields = identity.get_fields(obj, namespaces, decoders=decoders) except (XMLSchemaValueError, XMLSchemaTypeError) as err: yield self.validation_error(validation, err, obj, **kwargs) else: if any(x is not None for x in fields) or nilled: try: counter.increase(fields) except ValueError as err: yield self.validation_error(validation, err, obj, **kwargs) # Apply non XSD optional validations if 'extra_validator' in kwargs: try: result = kwargs['extra_validator'](obj, self) except XMLSchemaValidationError as err: yield self.validation_error(validation, err, obj, **kwargs) else: if isinstance(result, GeneratorType): for error in result: yield self.validation_error(validation, error, obj, **kwargs) # Disable collect for out of scope identities and check key references if 'max_depth' not in kwargs: for identity in self.identities.values(): counter = identities[identity] counter.enabled = False if isinstance(identity, XsdKeyref): for error in counter.iter_errors(identities): yield self.validation_error(validation, error, obj, **kwargs) elif level: self.stop_identities(identities) def to_objects(self, obj: ElementType, with_bindings: bool = False, **kwargs: Any) \ -> DecodeType['dataobjects.DataElement']: """ Decodes XML data to Python data objects. :param obj: the XML data source. :param with_bindings: if `True` is provided the decoding is done using \ :class:`DataBindingConverter` that used XML data binding classes. For \ default the objects are instances of :class:`DataElement` and uses the \ :class:`DataElementConverter`. :param kwargs: other optional keyword arguments for the method \ :func:`iter_decode`, except the argument *converter*. """ if with_bindings: return self.decode(obj, converter=dataobjects.DataBindingConverter, **kwargs) return self.decode(obj, converter=dataobjects.DataElementConverter, **kwargs) def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[ElementType]: """ Creates an iterator for encoding data to an Element. :param obj: the data that has to be encoded. :param validation: the validation mode: can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the encoding process. :return: yields an Element, eventually preceded by a sequence of \ validation or encoding errors. """ errors: List[Union[str, Exception]] = [] try: converter = kwargs['converter'] except KeyError: converter = kwargs['converter'] = self.schema.get_converter(**kwargs) else: if not isinstance(converter, XMLSchemaConverter): converter = kwargs['converter'] = self.schema.get_converter(**kwargs) try: level = kwargs['level'] except KeyError: level = 0 element_data = converter.element_encode(obj, self, level) if not self.is_matching(element_data.tag, self.default_namespace): errors.append("data tag does not match XSD element name") if 'max_depth' in kwargs and kwargs['max_depth'] == 0: for e in errors: yield self.validation_error(validation, e, **kwargs) return else: element_data = converter.element_encode(obj, self, level) text = None children = element_data.content attributes = () xsd_type = self.get_type(element_data) if XSI_TYPE in element_data.attributes: type_name = element_data.attributes[XSI_TYPE].strip() try: xsd_type = self.maps.get_instance_type(type_name, xsd_type, converter) except (KeyError, TypeError) as err: errors.append(err) else: default_namespace = converter.get('') if default_namespace and not isinstance(xsd_type, XsdSimpleType): # Adjust attributes mapped into default namespace ns_part = '{%s}' % default_namespace for k in list(element_data.attributes): if not k.startswith(ns_part): continue elif k in xsd_type.attributes: continue local_name = k[len(ns_part):] if local_name in xsd_type.attributes: element_data.attributes[local_name] = element_data.attributes[k] del element_data.attributes[k] attribute_group = self.get_attributes(xsd_type) result: Any for result in attribute_group.iter_encode(element_data.attributes, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): errors.append(result) else: attributes = result if XSI_NIL in element_data.attributes: xsi_nil = element_data.attributes[XSI_NIL].strip() if not self.nillable: errors.append("element is not nillable.") elif xsi_nil not in {'0', '1', 'true', 'false'}: errors.append("xsi:nil attribute must has a boolean value.") elif xsi_nil in ('0', 'false'): pass elif self.fixed is not None: errors.append("xsi:nil='true' but the element has a fixed value.") elif element_data.text is not None or element_data.content: errors.append("xsi:nil='true' but the element is not empty.") else: elem = converter.etree_element(element_data.tag, attrib=attributes, level=level) for e in errors: yield self.validation_error(validation, e, elem, **kwargs) yield elem return if isinstance(xsd_type, XsdSimpleType): if element_data.content: errors.append("a simpleType element can't has child elements.") if element_data.text is not None: for result in xsd_type.iter_encode(element_data.text, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): errors.append(result) else: text = result elif self.fixed is not None: text = self.fixed elif self.default is not None and kwargs.get('use_defaults'): text = self.default elif xsd_type.has_simple_content(): if element_data.text is not None: for result in xsd_type.content.iter_encode(element_data.text, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): errors.append(result) else: text = result elif self.fixed is not None: text = self.fixed elif self.default is not None and kwargs.get('use_defaults'): text = self.default else: for result in xsd_type.content.iter_encode(element_data, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): errors.append(result) elif result: text, children = result elem = converter.etree_element(element_data.tag, text, children, attributes, level) if errors: for e in errors: yield self.validation_error(validation, e, elem, **kwargs) yield elem del element_data def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None, group: Optional['XsdGroup'] = None, **kwargs: Any) -> bool: if not name: return False elif default_namespace and name[0] != '{': qname = '{%s}%s' % (default_namespace, name) if name == self.name or qname == self.name: return True return any(name == e.name or qname == e.name for e in self.iter_substitutes()) elif name == self.name: return True else: return any(name == e.name for e in self.iter_substitutes()) def match(self, name: Optional[str], default_namespace: Optional[str] = None, **kwargs: Any) -> Optional['XsdElement']: if not name: return None elif default_namespace and name[0] != '{': qname = '{%s}%s' % (default_namespace, name) if name == self.name or qname == self.name: return self for xsd_element in self.iter_substitutes(): if name == xsd_element.name or qname == xsd_element.name: return xsd_element elif name == self.name: return self else: for xsd_element in self.iter_substitutes(): if name == xsd_element.name: return xsd_element return None def is_restriction(self, other: ModelParticleType, check_occurs: bool = True) -> bool: e: ModelParticleType if isinstance(other, XsdAnyElement): if self.min_occurs == self.max_occurs == 0: return True if check_occurs and not self.has_occurs_restriction(other): return False return other.is_matching(self.name, self.default_namespace) elif isinstance(other, XsdElement): if self.name != other.name: if other.name == self.substitution_group and \ other.min_occurs != other.max_occurs and \ self.max_occurs != 0 and not other.abstract \ and self.xsd_version == '1.0': # An UPA violation case. Base is the head element, it's not # abstract and has non deterministic occurs: this is less # restrictive than W3C test group (elemZ026), marked as # invalid despite it's based on an abstract declaration. # See also test case invalid_restrictions1.xsd. return False for e in other.iter_substitutes(): if e.name == self.name: break else: return False if check_occurs and not self.has_occurs_restriction(other): return False elif not self.is_consistent(other) and self.type.elem is not other.type.elem and \ not self.type.is_derived(other.type, 'restriction') and not other.type.abstract: return False elif other.fixed is not None and \ (self.fixed is None or self.type.normalize( self.fixed) != other.type.normalize(other.fixed)): return False elif other.nillable is False and self.nillable: return False elif any(value not in self.block for value in other.block.split()): return False elif not all(k in other.identities for k in self.identities): return False else: return True elif other.model == 'choice': if other.is_empty() and self.max_occurs != 0: return False check_group_items_occurs = self.xsd_version == '1.0' total_occurs = OccursCalculator() for e in other.iter_model(): if not isinstance(e, (XsdElement, XsdAnyElement)): return False elif not self.is_restriction(e, check_group_items_occurs): continue total_occurs += e total_occurs *= other if self.has_occurs_restriction(total_occurs): return True total_occurs.reset() return False else: match_restriction = False for e in other.iter_model(): if match_restriction: if not e.is_emptiable(): return False elif self.is_restriction(e): match_restriction = True elif not e.is_emptiable(): return False return True def is_overlap(self, other: SchemaElementType) -> bool: if isinstance(other, XsdElement): if self.name == other.name: return True elif other.substitution_group == self.name or other.name == self.substitution_group: return True elif isinstance(other, XsdAnyElement): if other.is_matching(self.name, self.default_namespace): return True for e in self.maps.substitution_groups.get(self.name, ()): if other.is_matching(e.name, self.default_namespace): return True return False def is_consistent(self, other: SchemaElementType, strict: bool = True) -> bool: """ Element Declarations Consistent check between two element particles. Ref: https://www.w3.org/TR/xmlschema-1/#cos-element-consistent :returns: `True` if there is no inconsistency between the particles, `False` otherwise, """ return self.name != other.name or self.type is other.type def is_single(self) -> bool: if self.parent is None: return True elif self.max_occurs != 1: return False elif self.parent.max_occurs == 1: return True else: return self.parent.model != 'choice' and len(self.parent) > 1 def is_empty(self) -> bool: return self.fixed == '' or self.type.is_empty() class Xsd11Element(XsdElement): """ Class for XSD 1.1 *element* declarations. .. <element abstract = boolean : false block = (#all | List of (extension | restriction | substitution)) default = string final = (#all | List of (extension | restriction)) fixed = string form = (qualified | unqualified) id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 name = NCName nillable = boolean : false ref = QName substitutionGroup = List of QName targetNamespace = anyURI type = QName {any attributes with non-schema namespace . . .}> Content: (annotation?, ((simpleType | complexType)?, alternative*, (unique | key | keyref)*)) </element> """ _target_namespace: Optional[str] = None def _parse(self) -> None: if not self._build: return self._parse_particle(self.elem) self._parse_attributes() if self.ref is None: self._parse_type() self._parse_alternatives() self._parse_constraints() if self.parent is None and 'substitutionGroup' in self.elem.attrib: for substitution_group in self.elem.attrib['substitutionGroup'].split(): self._parse_substitution_group(substitution_group) self._parse_target_namespace() if any(v.inheritable for v in self.attributes.values()): self.inheritable = {} for k, v in self.attributes.items(): if k is not None and isinstance(v, XsdAttribute): if v.inheritable: self.inheritable[k] = v def _parse_alternatives(self) -> None: alternatives = [] has_test = True for child in self.elem: if child.tag == XSD_ALTERNATIVE: alternatives.append(XsdAlternative(child, self.schema, self)) if not has_test: self.parse_error("test attribute missing on non-final alternative") has_test = 'test' in child.attrib if alternatives: self.alternatives = alternatives @property def built(self) -> bool: return (self.type.parent is None or self.type.built) and \ all(c.built for c in self.identities.values()) and \ all(a.built for a in self.alternatives) @property def target_namespace(self) -> str: if self._target_namespace is not None: return self._target_namespace elif self.ref is not None: return self.ref.target_namespace else: return self.schema.target_namespace def iter_components(self, xsd_classes: ComponentClassType = None) -> Iterator[XsdComponent]: if xsd_classes is None: yield self yield from self.identities.values() else: if isinstance(self, xsd_classes): yield self for obj in self.identities.values(): if isinstance(obj, xsd_classes): yield obj for alt in self.alternatives: yield from alt.iter_components(xsd_classes) if self.ref is None and self.type.parent is not None: yield from self.type.iter_components(xsd_classes) def iter_substitutes(self) -> Iterator[XsdElement]: if self.parent is None or self.ref is not None: for xsd_element in self.maps.substitution_groups.get(self.name, ()): yield xsd_element yield from xsd_element.iter_substitutes() def get_type(self, elem: Union[ElementType, ElementData], inherited: Optional[Dict[str, Any]] = None) -> BaseXsdType: if not self.alternatives: return self._head_type or self.type if isinstance(elem, ElementData): if elem.attributes: attrib: Dict[str, str] = {} for k, v in elem.attributes.items(): value = raw_xml_encode(v) if value is not None: attrib[k] = value elem = etree_element(elem.tag, attrib=attrib) else: elem = etree_element(elem.tag) if inherited: dummy = etree_element('_dummy_element', attrib=inherited) dummy.attrib.update(elem.attrib) for alt in self.alternatives: if alt.type is not None: if alt.token is None or alt.test(elem) or alt.test(dummy): return alt.type else: for alt in self.alternatives: if alt.type is not None: if alt.token is None or alt.test(elem): return alt.type return self._head_type or self.type def is_overlap(self, other: SchemaElementType) -> bool: if isinstance(other, XsdElement): if self.name == other.name: return True elif any(self.name == x.name for x in other.iter_substitutes()): return True for e in self.iter_substitutes(): if other.name == e.name or any(x is e for x in other.iter_substitutes()): return True elif isinstance(other, XsdAnyElement): if other.is_matching(self.name, self.default_namespace): return True for e in self.maps.substitution_groups.get(self.name, ()): if other.is_matching(e.name, self.default_namespace): return True return False def is_consistent(self, other: SchemaElementType, strict: bool = True) -> bool: if isinstance(other, XsdAnyElement): if other.process_contents == 'skip': return True xsd_element = other.match(self.name, self.default_namespace, resolve=True) return xsd_element is None or self.is_consistent(xsd_element, strict=False) e1: XsdElement = self e2 = other if self.name != other.name: for e1 in self.iter_substitutes(): if e1.name == other.name: break else: for e2 in other.iter_substitutes(): if e2.name == self.name: break else: return True if len(e1.alternatives) != len(e2.alternatives): return False elif e1.type is not e2.type and strict: return False elif e1.type is not e2.type or \ not all(any(a == x for x in e2.alternatives) for a in e1.alternatives) or \ not all(any(a == x for x in e1.alternatives) for a in e2.alternatives): msg = "Maybe a not equivalent type table between elements %r and %r." % (e1, e2) warnings.warn(msg, XMLSchemaTypeTableWarning, stacklevel=3) return True class XsdAlternative(XsdComponent): """ XSD 1.1 type *alternative* definitions. .. <alternative id = ID test = an XPath expression type = QName xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local)) {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleType | complexType)?) </alternative> """ parent: XsdElement type: BaseXsdType path: Optional[str] = None token: Optional[XPathToken] = None _ADMITTED_TAGS = {XSD_ALTERNATIVE} def __init__(self, elem: ElementType, schema: SchemaType, parent: XsdElement) -> None: super(XsdAlternative, self).__init__(elem, schema, parent) def __repr__(self) -> str: return '%s(type=%r, test=%r)' % ( self.__class__.__name__, self.elem.get('type'), self.elem.get('test') ) def __eq__(self, other: object) -> bool: return isinstance(other, XsdAlternative) and \ self.path == other.path and self.type is other.type and \ self.xpath_default_namespace == other.xpath_default_namespace def __ne__(self, other: object) -> bool: return not isinstance(other, XsdAlternative) or \ self.path != other.path or self.type is not other.type or \ self.xpath_default_namespace != other.xpath_default_namespace def _parse(self) -> None: attrib = self.elem.attrib if 'xpathDefaultNamespace' in attrib: self.xpath_default_namespace = self._parse_xpath_default_namespace(self.elem) else: self.xpath_default_namespace = self.schema.xpath_default_namespace parser = XPath2Parser( namespaces=self.namespaces, strict=False, default_namespace=self.xpath_default_namespace ) try: self.path = attrib['test'] except KeyError: pass # an absent test is not an error, it should be the default type else: try: self.token = parser.parse(self.path) except ElementPathError as err: self.parse_error(err) self.token = parser.parse('false()') self.path = 'false()' try: type_qname = self.schema.resolve_qname(attrib['type']) except (KeyError, ValueError, RuntimeError) as err: if 'type' in attrib: self.parse_error(err) self.type = self.any_type else: child = self._parse_child_component(self.elem, strict=False) if child is None or child.tag not in (XSD_COMPLEX_TYPE, XSD_SIMPLE_TYPE): self.parse_error("missing 'type' attribute") self.type = self.any_type elif child.tag == XSD_COMPLEX_TYPE: self.type = self.schema.xsd_complex_type_class(child, self.schema, self) else: self.type = self.schema.simple_type_factory(child, self.schema, self) if not self.type.is_derived(self.parent.type): msg = "declared type is not derived from {!r}" self.parse_error(msg.format(self.parent.type)) else: try: self.type = self.maps.lookup_type(type_qname) except KeyError: self.parse_error("unknown type %r" % attrib['type']) self.type = self.any_type else: if self.type.name != XSD_ERROR and not self.type.is_derived(self.parent.type): msg = "type {!r} is not derived from {!r}" self.parse_error(msg.format(attrib['type'], self.parent.type)) child = self._parse_child_component(self.elem, strict=False) if child is not None and child.tag in (XSD_COMPLEX_TYPE, XSD_SIMPLE_TYPE): self.parse_error("the attribute 'type' and the <%s> local declaration " "are mutually exclusive" % child.tag.split('}')[-1]) @property def built(self) -> bool: if not hasattr(self, 'type'): return False return self.type.parent is None or self.type.built @property def validation_attempted(self) -> str: if self.built: return 'full' elif not hasattr(self, 'type'): return 'none' else: return self.type.validation_attempted def iter_components(self, xsd_classes: ComponentClassType = None) -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self if self.type is not None and self.type.parent is not None: yield from self.type.iter_components(xsd_classes) def test(self, elem: ElementType) -> bool: if self.token is None: return False try: result = list(self.token.select(context=XPathContext(elem))) return self.token.boolean_value(result) except (TypeError, ValueError): return False ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/exceptions.py�������������������������������������������������0000664�0000000�0000000�00000035130�14211403446�0022437�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from typing import TYPE_CHECKING, Any, Optional, cast, Iterable, Union, Callable from ..exceptions import XMLSchemaException, XMLSchemaWarning, XMLSchemaValueError from ..etree import etree_tostring from ..aliases import ElementType, NamespacesType, SchemaElementType, ModelParticleType from ..helpers import get_prefixed_qname, etree_getpath, is_etree_element if TYPE_CHECKING: from ..resources import XMLResource from .xsdbase import XsdValidator from .groups import XsdGroup ValidatorType = Union['XsdValidator', Callable[[Any], None]] class XMLSchemaValidatorError(XMLSchemaException): """ Base class for XSD validator errors. :param validator: the XSD validator. :param message: the error message. :param elem: the element that contains the error. :param source: the XML resource that contains the error. :param namespaces: is an optional mapping from namespace prefix to URI. """ _path: Optional[str] def __init__(self, validator: ValidatorType, message: str, elem: Optional[ElementType] = None, source: Optional['XMLResource'] = None, namespaces: Optional[NamespacesType] = None) -> None: self._path = None self.validator = validator self.message = message[:-1] if message[-1] in ('.', ':') else message self.namespaces = namespaces self.source = source self.elem = elem def __str__(self) -> str: if self.elem is None: return self.message msg = ['%s:\n' % self.message] elem_as_string = cast(str, etree_tostring(self.elem, self.namespaces, ' ', 20)) msg.append("Schema:\n\n%s\n" % elem_as_string) path = self.path if path is not None: msg.append("Path: %s\n" % path) if self.schema_url is not None: msg.append("Schema URL: %s\n" % self.schema_url) if self.origin_url not in (None, self.schema_url): msg.append("Origin URL: %s\n" % self.origin_url) return '\n'.join(msg) @property def msg(self) -> str: return self.__str__() def __setattr__(self, name: str, value: Any) -> None: if name == 'elem' and value is not None: if not is_etree_element(value): raise XMLSchemaValueError( "'elem' attribute requires an Element, not %r." % type(value) ) if self.source is not None: self._path = etree_getpath( elem=value, root=self.source.root, namespaces=self.namespaces, relative=False, add_position=True ) if self.source.is_lazy(): value = None # Don't save the element of a lazy resource super(XMLSchemaValidatorError, self).__setattr__(name, value) @property def sourceline(self) -> Any: """XML element *sourceline* if available (lxml Element) and *elem* is set.""" return getattr(self.elem, 'sourceline', None) @property def root(self) -> Optional[ElementType]: """The XML resource root element if *source* is set.""" try: return self.source.root # type: ignore[union-attr] except AttributeError: return None @property def schema_url(self) -> Optional[str]: """The schema URL, if available and the *validator* is an XSD component.""" url: Optional[str] try: url = self.validator.schema.source.url # type: ignore[union-attr] except AttributeError: return None else: return url @property def origin_url(self) -> Optional[str]: """The origin schema URL, if available and the *validator* is an XSD component.""" url: Optional[str] try: url = self.validator.maps.validator.source.url # type: ignore[union-attr] except AttributeError: return None else: return url @property def path(self) -> Optional[str]: """The XPath of the element, if it's not `None` and the XML resource is set.""" if self.elem is None or self.source is None: return self._path return etree_getpath( elem=self.elem, root=self.source.root, namespaces=self.namespaces, relative=False, add_position=True ) class XMLSchemaNotBuiltError(XMLSchemaValidatorError, RuntimeError): """ Raised when there is an improper usage attempt of a not built XSD validator. :param validator: the XSD validator. :param message: the error message. """ def __init__(self, validator: 'XsdValidator', message: str) -> None: super(XMLSchemaNotBuiltError, self).__init__( validator=validator, message=message, elem=getattr(validator, 'elem', None), source=getattr(validator, 'source', None), namespaces=getattr(validator, 'namespaces', None) ) class XMLSchemaParseError(XMLSchemaValidatorError, SyntaxError): # type: ignore[misc] """ Raised when an error is found during the building of an XSD validator. :param validator: the XSD validator. :param message: the error message. :param elem: the element that contains the error. """ def __init__(self, validator: 'XsdValidator', message: str, elem: Optional[ElementType] = None) -> None: super(XMLSchemaParseError, self).__init__( validator=validator, message=message, elem=elem if elem is not None else getattr(validator, 'elem', None), source=getattr(validator, 'source', None), namespaces=getattr(validator, 'namespaces', None), ) class XMLSchemaModelError(XMLSchemaValidatorError, ValueError): """ Raised when a model error is found during the checking of a model group. :param group: the XSD model group. :param message: the error message. """ def __init__(self, group: 'XsdGroup', message: str) -> None: super(XMLSchemaModelError, self).__init__( validator=group, message=message, elem=getattr(group, 'elem', None), source=getattr(group, 'source', None), namespaces=getattr(group, 'namespaces', None) ) class XMLSchemaModelDepthError(XMLSchemaModelError): """Raised when recursion depth is exceeded while iterating a model group.""" def __init__(self, group: 'XsdGroup') -> None: msg = "maximum model recursion depth exceeded while iterating {!r}".format(group) super(XMLSchemaModelDepthError, self).__init__(group, message=msg) class XMLSchemaValidationError(XMLSchemaValidatorError, ValueError): """ Raised when the XML data is not validated with the XSD component or schema. It's used by decoding and encoding methods. Encoding validation errors do not include XML data element and source, so the error is limited to a message containing object representation and a reason. :param validator: the XSD validator. :param obj: the not validated XML data. :param reason: the detailed reason of failed validation. :param source: the XML resource that contains the error. :param namespaces: is an optional mapping from namespace prefix to URI. """ def __init__(self, validator: ValidatorType, obj: Any, reason: Optional[str] = None, source: Optional['XMLResource'] = None, namespaces: Optional[NamespacesType] = None) -> None: if not isinstance(obj, str): _obj = obj else: _obj = obj.encode('ascii', 'xmlcharrefreplace').decode('utf-8') super(XMLSchemaValidationError, self).__init__( validator=validator, message="failed validating {!r} with {!r}".format(_obj, validator), elem=obj if is_etree_element(obj) else None, source=source, namespaces=namespaces, ) self.obj = obj self.reason = reason def __repr__(self) -> str: return '%s(reason=%r)' % (self.__class__.__name__, self.reason) def __str__(self) -> str: msg = ['%s:\n' % self.message] if self.reason is not None: msg.append('Reason: %s\n' % self.reason) if hasattr(self.validator, 'tostring'): chunk = self.validator.tostring(' ', 20) # type: ignore[union-attr] msg.append("Schema:\n\n%s\n" % chunk) if self.elem is not None and is_etree_element(self.elem): try: elem_as_string = cast(str, etree_tostring(self.elem, self.namespaces, ' ', 20)) except (ValueError, TypeError): # pragma: no cover elem_as_string = repr(self.elem) # pragma: no cover if hasattr(self.elem, 'sourceline'): line = getattr(self.elem, 'sourceline') msg.append("Instance (line %r):\n\n%s\n" % (line, elem_as_string)) else: msg.append("Instance:\n\n%s\n" % elem_as_string) if self.path is not None: msg.append("Path: %s\n" % self.path) if len(msg) == 1: return msg[0][:-2] return '\n'.join(msg) class XMLSchemaDecodeError(XMLSchemaValidationError): """ Raised when an XML data string is not decodable to a Python object. :param validator: the XSD validator. :param obj: the not validated XML data. :param decoder: the XML data decoder. :param reason: the detailed reason of failed validation. :param source: the XML resource that contains the error. :param namespaces: is an optional mapping from namespace prefix to URI. """ message = "failed decoding {!r} with {!r}.\n" def __init__(self, validator: Union['XsdValidator', Callable[[Any], None]], obj: Any, decoder: Any, reason: Optional[str] = None, source: Optional['XMLResource'] = None, namespaces: Optional[NamespacesType] = None) -> None: super(XMLSchemaDecodeError, self).__init__(validator, obj, reason, source, namespaces) self.decoder = decoder class XMLSchemaEncodeError(XMLSchemaValidationError): """ Raised when an object is not encodable to an XML data string. :param validator: the XSD validator. :param obj: the not validated XML data. :param encoder: the XML encoder. :param reason: the detailed reason of failed validation. :param source: the XML resource that contains the error. :param namespaces: is an optional mapping from namespace prefix to URI. """ message = "failed encoding {!r} with {!r}.\n" def __init__(self, validator: Union['XsdValidator', Callable[[Any], None]], obj: Any, encoder: Any, reason: Optional[str] = None, source: Optional['XMLResource'] = None, namespaces: Optional[NamespacesType] = None) -> None: super(XMLSchemaEncodeError, self).__init__(validator, obj, reason, source, namespaces) self.encoder = encoder class XMLSchemaChildrenValidationError(XMLSchemaValidationError): """ Raised when a child element is not validated. :param validator: the XSD validator. :param elem: the not validated XML element. :param index: the child index. :param particle: the model particle that generated the error. Maybe the validator itself. :param occurs: the particle occurrences. :param expected: the expected element tags/object names. :param source: the XML resource that contains the error. :param namespaces: is an optional mapping from namespace prefix to URI. """ def __init__(self, validator: 'XsdValidator', elem: ElementType, index: int, particle: ModelParticleType, occurs: int = 0, expected: Optional[Iterable[SchemaElementType]] = None, source: Optional['XMLResource'] = None, namespaces: Optional[NamespacesType] = None) -> None: self.index = index self.particle = particle self.occurs = occurs self.expected = expected tag = get_prefixed_qname(elem.tag, validator.namespaces, use_empty=False) if index >= len(elem): reason = "The content of element %r is not complete." % tag else: child_tag = get_prefixed_qname(elem[index].tag, validator.namespaces, use_empty=False) reason = "Unexpected child with tag %r at position %d." % (child_tag, index + 1) if occurs and particle.is_missing(occurs): reason += " The particle %r occurs %d times but the minimum is %d." % ( particle, occurs, particle.min_occurs ) elif particle.is_over(occurs): reason += " The particle %r occurs %r times but the maximum is %r." % ( particle, occurs, particle.max_occurs ) if expected is None: pass else: expected_tags = [] for xsd_element in expected: name = xsd_element.prefixed_name if name is not None: expected_tags.append(name) elif getattr(xsd_element, 'process_contents', '') == 'strict': expected_tags.append( 'from %r namespace/s' % xsd_element.namespace # type: ignore[union-attr] ) if not expected_tags: pass elif len(expected_tags) > 1: reason += " Tag (%s) expected." % ' | '.join(repr(tag) for tag in expected_tags) elif expected_tags[0].startswith('from '): reason += " Tag %s expected." % expected_tags[0] else: reason += " Tag %r expected." % expected_tags[0] super(XMLSchemaChildrenValidationError, self).\ __init__(validator, elem, reason, source, namespaces) class XMLSchemaIncludeWarning(XMLSchemaWarning): """A schema include fails.""" class XMLSchemaImportWarning(XMLSchemaWarning): """A schema namespace import fails.""" class XMLSchemaTypeTableWarning(XMLSchemaWarning): """Not equivalent type table found in model.""" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/facets.py�����������������������������������������������������0000664�0000000�0000000�00000075331�14211403446�0021532�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains declarations and classes for XML Schema constraint facets. """ import re import math import operator from abc import abstractmethod from typing import TYPE_CHECKING, cast, Any, List, Optional, Pattern, Union, \ MutableSequence, overload, Tuple from elementpath import XPath2Parser, XPathContext, ElementPathError, \ translate_pattern, RegexError from ..names import XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_ENUMERATION, \ XSD_INTEGER, XSD_WHITE_SPACE, XSD_PATTERN, XSD_MAX_INCLUSIVE, XSD_MAX_EXCLUSIVE, \ XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_TOTAL_DIGITS, XSD_FRACTION_DIGITS, \ XSD_ASSERTION, XSD_DECIMAL, XSD_EXPLICIT_TIMEZONE, XSD_NOTATION_TYPE, XSD_QNAME, \ XSD_ANNOTATION from ..etree import etree_element from ..aliases import ElementType, SchemaType, AtomicValueType, BaseXsdType from ..helpers import count_digits, local_name from .exceptions import XMLSchemaValidationError, XMLSchemaDecodeError from .xsdbase import XsdComponent, XsdAnnotation if TYPE_CHECKING: from .simple_types import XsdList, XsdAtomicRestriction LaxDecodeType = Tuple[Any, List[XMLSchemaValidationError]] class XsdFacet(XsdComponent): """ XML Schema constraining facets base class. """ value: Optional[AtomicValueType] base_type: Optional[BaseXsdType] base_value: Optional[AtomicValueType] fixed = False def __init__(self, elem: ElementType, schema: SchemaType, parent: Union['XsdList', 'XsdAtomicRestriction'], base_type: Optional[BaseXsdType]) -> None: self.base_type = base_type super(XsdFacet, self).__init__(elem, schema, parent) def __repr__(self) -> str: return '%s(value=%r, fixed=%r)' % (self.__class__.__name__, self.value, self.fixed) def __call__(self, value: Any) -> None: try: self._validator(value) except TypeError: reason = "invalid type {!r} provided".format(type(value)) raise XMLSchemaValidationError(self, value, reason) from None @staticmethod def _validator(_: Any) -> None: return def _parse(self) -> None: if 'fixed' in self.elem.attrib and self.elem.attrib['fixed'] in ('true', '1'): self.fixed = True base_facet = self.base_facet self.base_value = None if base_facet is None else base_facet.value try: self._parse_value(self.elem) except (KeyError, ValueError, XMLSchemaDecodeError) as err: self.value = None self.parse_error(err) else: if base_facet is not None and base_facet.fixed and \ base_facet.value is not None and self.value != base_facet.value: self.parse_error("{!r} facet value is fixed to {!r}" .format(local_name(self.elem.tag), base_facet.value)) def _parse_value(self, elem: ElementType) -> Union[None, AtomicValueType, Pattern[str]]: self.value = elem.attrib['value'] # pragma: no cover return None @property def built(self) -> bool: return True # pragma: no cover @property def base_facet(self) -> Optional['XsdFacet']: """ An object of the same type if the instance has a base facet, `None` otherwise. """ base_type: Optional[BaseXsdType] = self.base_type tag = self.elem.tag while True: if base_type is None: return None try: base_facet = base_type.facets[tag] # type: ignore[union-attr] except (AttributeError, KeyError): base_type = base_type.base_type else: assert isinstance(base_facet, self.__class__) return base_facet class XsdWhiteSpaceFacet(XsdFacet): """ XSD *whiteSpace* facet. .. <whiteSpace fixed = boolean : false id = ID value = (collapse | preserve | replace) {any attributes with non-schema namespace . . .}> Content: (annotation?) </whiteSpace> """ value: str _ADMITTED_TAGS = XSD_WHITE_SPACE, def _parse_value(self, elem: ElementType) -> None: self.value = elem.attrib['value'] if self.value == 'collapse': self._validator = self.collapse_white_space_validator # type: ignore[assignment] elif self.value == 'replace': if self.base_value == 'collapse': self.parse_error("facet value can be only 'collapse'") self._validator = self.replace_white_space_validator # type: ignore[assignment] elif self.base_value == 'collapse': self.parse_error("facet value can be only 'collapse'") elif self.base_value == 'replace': self.parse_error("facet value can be only 'replace' or 'collapse'") def replace_white_space_validator(self, value: str) -> None: if '\t' in value or '\n' in value: raise XMLSchemaValidationError( self, value, "value contains tabs or newlines" ) def collapse_white_space_validator(self, value: str) -> None: if '\t' in value or '\n' in value or ' ' in value: raise XMLSchemaValidationError( self, value, "value contains non collapsed white spaces" ) class XsdLengthFacet(XsdFacet): """ XSD *length* facet. .. <length fixed = boolean : false id = ID value = nonNegativeInteger {any attributes with non-schema namespace . . .}> Content: (annotation?) </length> """ value: int base_type: BaseXsdType base_value: Optional[int] _ADMITTED_TAGS = XSD_LENGTH, def _parse_value(self, elem: ElementType) -> None: self.value = int(elem.attrib['value']) if self.base_value is not None and self.value != self.base_value: self.parse_error("base facet has a different length ({})".format(self.base_value)) primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 self._validator = self._length_validator # type: ignore[assignment] def _length_validator(self, value: Any) -> None: if len(value) != self.value: reason = "length has to be {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) class XsdMinLengthFacet(XsdFacet): """ XSD *minLength* facet. .. <minLength fixed = boolean : false id = ID value = nonNegativeInteger {any attributes with non-schema namespace . . .}> Content: (annotation?) </minLength> """ value: int base_type: BaseXsdType base_value: Optional[int] _ADMITTED_TAGS = XSD_MIN_LENGTH, def _parse_value(self, elem: ElementType) -> None: self.value = int(elem.attrib['value']) if self.base_value is not None and self.value < self.base_value: self.parse_error("base facet has a greater min length ({})".format(self.base_value)) primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 self._validator = self._min_length_validator # type: ignore[assignment] def _min_length_validator(self, value: Any) -> None: if len(value) < self.value: reason = "value length cannot be lesser than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) class XsdMaxLengthFacet(XsdFacet): """ XSD *maxLength* facet. .. <maxLength fixed = boolean : false id = ID value = nonNegativeInteger {any attributes with non-schema namespace . . .}> Content: (annotation?) </maxLength> """ value: int base_type: BaseXsdType base_value: Optional[int] _ADMITTED_TAGS = XSD_MAX_LENGTH, def _parse_value(self, elem: ElementType) -> None: self.value = int(elem.attrib['value']) if self.base_value is not None and self.value > self.base_value: self.parse_error("base type has a lesser max length ({})".format(self.base_value)) primitive_type = getattr(self.base_type, 'primitive_type', None) if primitive_type is None or primitive_type.name not in {XSD_QNAME, XSD_NOTATION_TYPE}: # See: https://www.w3.org/Bugs/Public/show_bug.cgi?id=4009 self._validator = self._max_length_validator # type: ignore[assignment] def _max_length_validator(self, value: Any) -> None: if len(value) > self.value: reason = "value length cannot be greater than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) class XsdMinInclusiveFacet(XsdFacet): """ XSD *minInclusive* facet. .. <minInclusive fixed = boolean : false id = ID value = anySimpleType {any attributes with non-schema namespace . . .}> Content: (annotation?) </minInclusive> """ base_type: BaseXsdType _ADMITTED_TAGS = XSD_MIN_INCLUSIVE, def _parse_value(self, elem: ElementType) -> None: value = elem.attrib['value'] self.value, errors = cast(LaxDecodeType, self.base_type.decode(value, 'lax')) for e in errors: self.parse_error("invalid restriction: {}".format(e.reason)) def __call__(self, value: Any) -> None: try: if value < self.value: reason = "value has to be greater or equal than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) except TypeError as err: raise XMLSchemaValidationError(self, value, str(err)) from None class XsdMinExclusiveFacet(XsdFacet): """ XSD *minExclusive* facet. .. <minExclusive fixed = boolean : false id = ID value = anySimpleType {any attributes with non-schema namespace . . .}> Content: (annotation?) </minExclusive> """ base_type: BaseXsdType _ADMITTED_TAGS = XSD_MIN_EXCLUSIVE, def _parse_value(self, elem: ElementType) -> None: value = elem.attrib['value'] self.value, errors = cast(LaxDecodeType, self.base_type.decode(value, 'lax')) for e in errors: if not isinstance(e.validator, self.__class__) or e.validator.value != self.value: self.parse_error("invalid restriction: {}".format(e.reason)) facet: Any = self.base_type.get_facet(XSD_MAX_INCLUSIVE) if facet is not None and facet.value == self.value: self.parse_error("invalid restriction: {} is also the maximum".format(self.value)) def __call__(self, value: Any) -> None: try: if value <= self.value: reason = "value has to be greater than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) except TypeError as err: raise XMLSchemaValidationError(self, value, str(err)) from None class XsdMaxInclusiveFacet(XsdFacet): """ XSD *maxInclusive* facet. .. <maxInclusive fixed = boolean : false id = ID value = anySimpleType {any attributes with non-schema namespace . . .}> Content: (annotation?) </maxInclusive> """ base_type: BaseXsdType _ADMITTED_TAGS = XSD_MAX_INCLUSIVE, def _parse_value(self, elem: ElementType) -> None: value = elem.attrib['value'] self.value, errors = cast(LaxDecodeType, self.base_type.decode(value, 'lax')) for e in errors: self.parse_error("invalid restriction: {}".format(e.reason)) def __call__(self, value: Any) -> None: try: if value > self.value: reason = "value has to be lesser or equal than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) except TypeError as err: raise XMLSchemaValidationError(self, value, str(err)) from None class XsdMaxExclusiveFacet(XsdFacet): """ XSD *maxExclusive* facet. .. <maxExclusive fixed = boolean : false id = ID value = anySimpleType {any attributes with non-schema namespace . . .}> Content: (annotation?) </maxExclusive> """ base_type: BaseXsdType _ADMITTED_TAGS = XSD_MAX_EXCLUSIVE, def _parse_value(self, elem: ElementType) -> None: value = elem.attrib['value'] self.value, errors = cast(LaxDecodeType, self.base_type.decode(value, 'lax')) for e in errors: if not isinstance(e.validator, self.__class__) or e.validator.value != self.value: self.parse_error("invalid restriction: {}".format(e.reason)) facet: Any = self.base_type.get_facet(XSD_MIN_INCLUSIVE) if facet is not None and facet.value == self.value: self.parse_error("invalid restriction: {} is also the minimum".format(self.value)) def __call__(self, value: Any) -> None: try: if value >= self.value: reason = "value has to be lesser than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) except TypeError as err: raise XMLSchemaValidationError(self, value, str(err)) from None class XsdTotalDigitsFacet(XsdFacet): """ XSD *totalDigits* facet. .. <totalDigits fixed = boolean : false id = ID value = positiveInteger {any attributes with non-schema namespace . . .}> Content: (annotation?) </totalDigits> """ value: int base_type: BaseXsdType _ADMITTED_TAGS = XSD_TOTAL_DIGITS, def _parse_value(self, elem: ElementType) -> None: # Errors are detected by meta-schema validation. For schemas with # 'lax' validation mode use 9999 in case of an invalid value. try: self.value = int(elem.attrib['value']) except (ValueError, KeyError): self.value = 9999 else: if self.value < 1: self.value = 9999 facet: Any = self.base_type.get_facet(XSD_TOTAL_DIGITS) if facet is not None and facet.value < self.value: self.parse_error( "invalid restriction: base value is lower ({})".format(facet.value) ) def __call__(self, value: Any) -> None: try: if operator.add(*count_digits(value)) <= self.value: return except (TypeError, ValueError, ArithmeticError) as err: raise XMLSchemaValidationError(self, value, str(err)) from None else: reason = "the number of digits has to be lesser or equal " \ "than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) class XsdFractionDigitsFacet(XsdFacet): """ XSD *fractionDigits* facet. .. <fractionDigits fixed = boolean : false id = ID value = nonNegativeInteger {any attributes with non-schema namespace . . .}> Content: (annotation?) </fractionDigits> """ value: int base_type: BaseXsdType _ADMITTED_TAGS = XSD_FRACTION_DIGITS, def __init__(self, elem: ElementType, schema: SchemaType, parent: 'XsdAtomicRestriction', base_type: BaseXsdType) -> None: super(XsdFractionDigitsFacet, self).__init__(elem, schema, parent, base_type) if not base_type.is_derived(self.maps.types[XSD_DECIMAL]): self.parse_error( "fractionDigits facet can be applied only to types derived from xs:decimal" ) def _parse_value(self, elem: ElementType) -> None: # Errors are detected by meta-schema validation. For schemas with # 'lax' validation mode use 9999 in case of an invalid value. try: self.value = int(elem.attrib['value']) except (ValueError, KeyError): self.value = 9999 else: if self.value < 0: self.value = 9999 elif self.value > 0 and self.base_type.is_derived(self.maps.types[XSD_INTEGER]): raise ValueError("fractionDigits facet value has to be 0 " "for types derived from xs:integer.") facet: Any = self.base_type.get_facet(XSD_FRACTION_DIGITS) if facet is not None and facet.value < self.value: self.parse_error( "invalid restriction: base value is lower ({})".format(facet.value) ) def __call__(self, value: Any) -> None: try: if count_digits(value)[1] <= self.value: return except (TypeError, ValueError, ArithmeticError) as err: raise XMLSchemaValidationError(self, value, str(err)) from None else: reason = "the number of fraction digits has to be lesser " \ "or equal than {!r}".format(self.value) raise XMLSchemaValidationError(self, value, reason) class XsdExplicitTimezoneFacet(XsdFacet): """ XSD 1.1 *explicitTimezone* facet. .. <explicitTimezone fixed = boolean : false id = ID value = NCName {any attributes with non-schema namespace . . .}> Content: (annotation?) </explicitTimezone> """ value: str base_type: BaseXsdType _ADMITTED_TAGS = XSD_EXPLICIT_TIMEZONE, def _parse_value(self, elem: ElementType) -> None: self.value = elem.attrib['value'] if self.value == 'prohibited': self._validator = self._prohibited_timezone_validator # type: ignore[assignment] elif self.value == 'required': self._validator = self._required_timezone_validator # type: ignore[assignment] elif self.value != 'optional': self.value = 'optional' # Error already detected by meta-schema validation facet: Any = self.base_type.get_facet(XSD_EXPLICIT_TIMEZONE) if facet is not None and facet.value != self.value and facet.value != 'optional': self.parse_error("invalid restriction from {!r}".format(facet.value)) def _required_timezone_validator(self, value: Any) -> None: if value.tzinfo is None: raise XMLSchemaValidationError( self, value, "time zone required for value {!r}".format(self.value) ) def _prohibited_timezone_validator(self, value: Any) -> None: if value.tzinfo is not None: raise XMLSchemaValidationError( self, value, "time zone prohibited for value {!r}".format(self.value) ) class XsdEnumerationFacets(MutableSequence[ElementType], XsdFacet): """ Sequence of XSD *enumeration* facets. Values are validates if match any of enumeration values. .. <enumeration id = ID value = anySimpleType {any attributes with non-schema namespace . . .}> Content: (annotation?) </enumeration> """ base_type: BaseXsdType _ADMITTED_TAGS = {XSD_ENUMERATION} def __init__(self, elem: ElementType, schema: SchemaType, parent: 'XsdAtomicRestriction', base_type: BaseXsdType) -> None: XsdFacet.__init__(self, elem, schema, parent, base_type) def _parse(self) -> None: self._elements = [self.elem] self.enumeration = [self._parse_value(self.elem)] def _parse_value(self, elem: ElementType) -> Optional[AtomicValueType]: try: value = self.base_type.decode(elem.attrib['value'], namespaces=self.schema.namespaces) except KeyError: pass # pragma: no cover (already detected by meta-schema validation) except XMLSchemaValidationError as err: self.parse_error(err, elem) else: if self.base_type.name == XSD_NOTATION_TYPE: assert isinstance(value, str) try: notation_qname = self.schema.resolve_qname(value) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err, elem) else: if notation_qname not in self.maps.notations: msg = "value {!r} must match a notation declaration" self.parse_error(msg.format(value), elem) return cast(AtomicValueType, value) return None @overload @abstractmethod def __getitem__(self, i: int) -> ElementType: ... @overload @abstractmethod def __getitem__(self, s: slice) -> MutableSequence[ElementType]: ... def __getitem__(self, i: Union[int, slice]) \ -> Union[ElementType, MutableSequence[ElementType]]: return self._elements[i] def __setitem__(self, i: Union[int, slice], o: Any) -> None: self._elements[i] = o if isinstance(i, int): self.enumeration[i] = self._parse_value(o) else: self.enumeration[i] = [self._parse_value(e) for e in o] def __delitem__(self, i: Union[int, slice]) -> None: del self._elements[i] del self.enumeration[i] def __len__(self) -> int: return len(self._elements) def insert(self, i: int, elem: ElementType) -> None: self._elements.insert(i, elem) self.enumeration.insert(i, self._parse_value(elem)) def __repr__(self) -> str: if len(self.enumeration) > 5: return '%s(%s)' % ( self.__class__.__name__, '[%s, ...]' % ', '.join(map(repr, self.enumeration[:5])) ) else: return '%s(%r)' % (self.__class__.__name__, self.enumeration) def __call__(self, value: Any) -> None: if value in self.enumeration: return try: if math.isnan(value): if any(math.isnan(x) for x in self.enumeration): # type: ignore[arg-type] return elif math.isinf(value): if any(math.isinf(x) and str(value) == str(x) # type: ignore[arg-type] for x in self.enumeration): # pragma: no cover return except TypeError: pass reason = "value must be one of {!r}".format(self.enumeration) raise XMLSchemaValidationError(self, value, reason) def get_annotation(self, i: int) -> Optional[XsdAnnotation]: """ Get the XSD annotation of the i-th enumeration facet. :param i: an integer index. :returns: an XsdAnnotation object or `None`. """ for child in self._elements[i]: if child.tag == XSD_ANNOTATION: return XsdAnnotation(child, self.schema, self) return None class XsdPatternFacets(MutableSequence[ElementType], XsdFacet): """ Sequence of XSD *pattern* facets. Values are validates if match any of patterns. .. <pattern id = ID value = string {any attributes with non-schema namespace . . .}> Content: (annotation?) </pattern> """ _ADMITTED_TAGS = {XSD_PATTERN} patterns: List[Pattern[str]] def __init__(self, elem: ElementType, schema: SchemaType, parent: 'XsdAtomicRestriction', base_type: Optional[BaseXsdType]) -> None: XsdFacet.__init__(self, elem, schema, parent, base_type) def _parse(self) -> None: self._elements = [self.elem] self.patterns = [self._parse_value(self.elem)] def _parse_value(self, elem: ElementType) -> Pattern[str]: try: python_pattern = translate_pattern( pattern=elem.attrib['value'], xsd_version=self.xsd_version, back_references=False, lazy_quantifiers=False, anchors=False ) return re.compile(python_pattern) except KeyError: return re.compile(r'^.*$') except (RegexError, re.error, XMLSchemaDecodeError) as err: self.parse_error(str(err), elem) return re.compile(r'^.*$') @overload @abstractmethod def __getitem__(self, i: int) -> ElementType: ... @overload @abstractmethod def __getitem__(self, s: slice) -> MutableSequence[ElementType]: ... def __getitem__(self, i: Union[int, slice]) \ -> Union[ElementType, MutableSequence[ElementType]]: return self._elements[i] def __setitem__(self, i: Union[int, slice], o: Any) -> None: self._elements[i] = o if isinstance(i, int): self.patterns[i] = self._parse_value(o) else: self.patterns[i] = [self._parse_value(e) for e in o] def __delitem__(self, i: Union[int, slice]) -> None: del self._elements[i] del self.patterns[i] def __len__(self) -> int: return len(self._elements) def insert(self, i: int, elem: ElementType) -> None: self._elements.insert(i, elem) self.patterns.insert(i, self._parse_value(elem)) def __repr__(self) -> str: s = repr(self.regexps) if len(s) < 70: return '%s(%s)' % (self.__class__.__name__, s) else: return '%s(%s...\'])' % (self.__class__.__name__, s[:70]) def __call__(self, text: str) -> None: try: if all(pattern.match(text) is None for pattern in self.patterns): reason = "value doesn't match any pattern of {!r}".format(self.regexps) raise XMLSchemaValidationError(self, text, reason) except TypeError as err: raise XMLSchemaValidationError(self, text, str(err)) from None @property def regexps(self) -> List[str]: return [e.attrib.get('value', '') for e in self._elements] def get_annotation(self, i: int) -> Optional[XsdAnnotation]: """ Get the XSD annotation of the i-th pattern facet. :param i: an integer index. :returns: an XsdAnnotation object or `None`. """ for child in self._elements[i]: if child.tag == XSD_ANNOTATION: return XsdAnnotation(child, self.schema, self) return None class XsdAssertionXPathParser(XPath2Parser): """Parser for XSD 1.1 assertion facets.""" XsdAssertionXPathParser.unregister('last') XsdAssertionXPathParser.unregister('position') # noinspection PyUnusedLocal @XsdAssertionXPathParser.method(XsdAssertionXPathParser.function('last', nargs=0)) def evaluate_last(self, context=None): # type: ignore[no-untyped-def] raise self.missing_context("context item size is undefined") # noinspection PyUnusedLocal @XsdAssertionXPathParser.method(XsdAssertionXPathParser.function('position', nargs=0)) def evaluate_position(self, context=None): # type: ignore[no-untyped-def] raise self.missing_context("context item position is undefined") class XsdAssertionFacet(XsdFacet): """ XSD 1.1 *assertion* facet for simpleType definitions. .. <assertion id = ID test = an XPath expression xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace | ##local)) {any attributes with non-schema namespace . . .}> Content: (annotation?) </assertion> """ _ADMITTED_TAGS = {XSD_ASSERTION} _root = etree_element('root') def __repr__(self) -> str: return '%s(test=%r)' % (self.__class__.__name__, self.path) def _parse(self) -> None: try: self.path = self.elem.attrib['test'] except KeyError: self.parse_error("missing attribute 'test'") self.path = 'true()' try: value = self.base_type.primitive_type.prefixed_name # type: ignore[union-attr] except AttributeError: value = self.any_simple_type.prefixed_name if 'xpathDefaultNamespace' in self.elem.attrib: self.xpath_default_namespace = self._parse_xpath_default_namespace(self.elem) else: self.xpath_default_namespace = self.schema.xpath_default_namespace self.parser = XsdAssertionXPathParser( namespaces=self.namespaces, strict=False, variable_types={'value': value}, default_namespace=self.xpath_default_namespace ) try: self.token = self.parser.parse(self.path) except ElementPathError as err: self.parse_error(err) self.token = self.parser.parse('true()') def __call__(self, value: AtomicValueType) -> None: context = XPathContext(self._root, variables={'value': value}) try: if not self.token.evaluate(context): reason = "value is not true with test path {!r}".format(self.path) raise XMLSchemaValidationError(self, value, reason) except ElementPathError as err: raise XMLSchemaValidationError(self, value, reason=str(err)) from None XSD_10_FACETS_BUILDERS = { XSD_WHITE_SPACE: XsdWhiteSpaceFacet, XSD_LENGTH: XsdLengthFacet, XSD_MIN_LENGTH: XsdMinLengthFacet, XSD_MAX_LENGTH: XsdMaxLengthFacet, XSD_MIN_INCLUSIVE: XsdMinInclusiveFacet, XSD_MIN_EXCLUSIVE: XsdMinExclusiveFacet, XSD_MAX_INCLUSIVE: XsdMaxInclusiveFacet, XSD_MAX_EXCLUSIVE: XsdMaxExclusiveFacet, XSD_TOTAL_DIGITS: XsdTotalDigitsFacet, XSD_FRACTION_DIGITS: XsdFractionDigitsFacet, XSD_ENUMERATION: XsdEnumerationFacets, XSD_PATTERN: XsdPatternFacets } XSD_11_FACETS_BUILDERS = XSD_10_FACETS_BUILDERS.copy() XSD_11_FACETS_BUILDERS.update({ XSD_ASSERTION: XsdAssertionFacet, XSD_EXPLICIT_TIMEZONE: XsdExplicitTimezoneFacet }) XSD_10_FACETS = set(XSD_10_FACETS_BUILDERS) XSD_11_FACETS = set(XSD_11_FACETS_BUILDERS) XSD_10_LIST_FACETS = {XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_PATTERN, XSD_ENUMERATION, XSD_WHITE_SPACE} XSD_11_LIST_FACETS = XSD_10_LIST_FACETS | {XSD_ASSERTION} XSD_10_UNION_FACETS = {XSD_PATTERN, XSD_ENUMERATION} XSD_11_UNION_FACETS = MULTIPLE_FACETS = {XSD_PATTERN, XSD_ENUMERATION, XSD_ASSERTION} XsdFacetType = Union[XsdLengthFacet, XsdMinLengthFacet, XsdMaxLengthFacet, XsdMinInclusiveFacet, XsdMinExclusiveFacet, XsdMaxInclusiveFacet, XsdMaxExclusiveFacet, XsdTotalDigitsFacet, XsdFractionDigitsFacet, XsdEnumerationFacets, XsdPatternFacets] �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/global_maps.py������������������������������������������������0000664�0000000�0000000�00000100140�14211403446�0022530�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains functions and classes for namespaces XSD declarations/definitions. """ import warnings from collections import Counter from functools import lru_cache from typing import cast, Any, Callable, Dict, List, Iterable, Iterator, \ MutableMapping, Optional, Set, Union, Tuple, Type from ..exceptions import XMLSchemaKeyError, XMLSchemaTypeError, XMLSchemaValueError, \ XMLSchemaRuntimeError, XMLSchemaWarning from ..names import XSD_NAMESPACE, XSD_REDEFINE, XSD_OVERRIDE, XSD_NOTATION, \ XSD_ANY_TYPE, XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE, XSD_GROUP, \ XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ELEMENT, XSI_TYPE from ..aliases import ComponentClassType, ElementType, SchemaType, BaseXsdType, \ SchemaGlobalType from ..helpers import get_qname, local_name, get_extended_qname from ..namespaces import NamespaceResourcesMap from .exceptions import XMLSchemaNotBuiltError, XMLSchemaModelError, XMLSchemaModelDepthError, \ XMLSchemaParseError from .xsdbase import XsdValidator, XsdComponent from .builtins import xsd_builtin_types_factory from . import XsdAttribute, XsdSimpleType, XsdComplexType, XsdElement, XsdAttributeGroup, \ XsdGroup, XsdNotation, XsdIdentity, XsdAssert, XsdUnion, XsdAtomicRestriction # # Defines the load functions for XML Schema structures def create_load_function(tag: str) \ -> Callable[[Dict[str, Any], Iterable[SchemaType]], None]: def load_xsd_globals(xsd_globals: Dict[str, Any], schemas: Iterable[SchemaType]) -> None: redefinitions = [] for schema in schemas: target_namespace = schema.target_namespace for elem in schema.root: if elem.tag not in {XSD_REDEFINE, XSD_OVERRIDE}: continue location = elem.get('schemaLocation') if location is None: continue for child in filter(lambda x: x.tag == tag and 'name' in x.attrib, elem): qname = get_qname(target_namespace, child.attrib['name']) redefinitions.append((qname, elem, child, schema, schema.includes[location])) for elem in filter(lambda x: x.tag == tag and 'name' in x.attrib, schema.root): qname = get_qname(target_namespace, elem.attrib['name']) if qname not in xsd_globals: xsd_globals[qname] = (elem, schema) else: try: other_schema = xsd_globals[qname][1] except (TypeError, IndexError): pass else: # It's ignored or replaced in case of an override if other_schema.override is schema: continue elif schema.override is other_schema: xsd_globals[qname] = (elem, schema) continue msg = "global {} with name={!r} is already defined" schema.parse_error(msg.format(local_name(tag), qname)) redefined_names = Counter(x[0] for x in redefinitions) for qname, elem, child, schema, redefined_schema in reversed(redefinitions): # Checks multiple redefinitions if redefined_names[qname] > 1: redefined_names[qname] = 1 redefined_schemas: Any redefined_schemas = [x[-1] for x in redefinitions if x[0] == qname] if any(redefined_schemas.count(x) > 1 for x in redefined_schemas): msg = "multiple redefinition for {} {!r}" schema.parse_error(msg.format(local_name(child.tag), qname), child) else: redefined_schemas = {x[-1]: x[-2] for x in redefinitions if x[0] == qname} for rs, s in redefined_schemas.items(): while True: try: s = redefined_schemas[s] except KeyError: break if s is rs: msg = "circular redefinition for {} {!r}" schema.parse_error(msg.format(local_name(child.tag), qname), child) break if elem.tag == XSD_OVERRIDE: # Components which match nothing in the target schema are ignored. See the # period starting with "Source declarations not present in the target set" # of the paragraph https://www.w3.org/TR/xmlschema11-1/#override-schema. if qname in xsd_globals: xsd_globals[qname] = (child, schema) else: # Append to a list if it's a redefine try: xsd_globals[qname].append((child, schema)) except KeyError: schema.parse_error("not a redefinition!", child) except AttributeError: xsd_globals[qname] = [xsd_globals[qname], (child, schema)] return load_xsd_globals load_xsd_simple_types = create_load_function(XSD_SIMPLE_TYPE) load_xsd_attributes = create_load_function(XSD_ATTRIBUTE) load_xsd_attribute_groups = create_load_function(XSD_ATTRIBUTE_GROUP) load_xsd_complex_types = create_load_function(XSD_COMPLEX_TYPE) load_xsd_elements = create_load_function(XSD_ELEMENT) load_xsd_groups = create_load_function(XSD_GROUP) load_xsd_notations = create_load_function(XSD_NOTATION) class XsdGlobals(XsdValidator): """ Mediator class for related XML schema instances. It stores the global declarations defined in the registered schemas. Register a schema to add its declarations to the global maps. :param validator: the origin schema class/instance used for creating the global maps. :param validation: the XSD validation mode to use, can be 'strict', 'lax' or 'skip'. """ types: Dict[str, Union[BaseXsdType, Tuple[ElementType, SchemaType]]] attributes: Dict[str, Union[XsdAttribute, Tuple[ElementType, SchemaType]]] attribute_groups: Dict[str, Union[XsdAttributeGroup, Tuple[ElementType, SchemaType]]] groups: Dict[str, Union[XsdGroup, Tuple[ElementType, SchemaType]]] notations: Dict[str, Union[XsdNotation, Tuple[ElementType, SchemaType]]] elements: Dict[str, Union[XsdElement, Tuple[ElementType, SchemaType]]] substitution_groups: Dict[str, Set[XsdElement]] identities: Dict[str, XsdIdentity] global_maps: Tuple[Dict[str, Any], ...] missing_locations: List[str] _lookup_function_resolver = { XSD_SIMPLE_TYPE: 'lookup_type', XSD_COMPLEX_TYPE: 'lookup_type', XSD_ELEMENT: 'lookup_element', XSD_GROUP: 'lookup_group', XSD_ATTRIBUTE: 'lookup_attribute', XSD_ATTRIBUTE_GROUP: 'lookup_attribute_group', XSD_NOTATION: 'lookup_notation', } def __init__(self, validator: SchemaType, validation: str = 'strict') -> None: super(XsdGlobals, self).__init__(validation) self.validator = validator self.namespaces = NamespaceResourcesMap() # Registered schemas by namespace URI self.missing_locations = [] # Missing or failing resource locations self.types = {} # Global types (both complex and simple) self.attributes = {} # Global attributes self.attribute_groups = {} # Attribute groups self.groups = {} # Model groups self.notations = {} # Notations self.elements = {} # Global elements self.substitution_groups = {} # Substitution groups self.identities = {} # Identity constraints (uniqueness, keys, keyref) self.global_maps = (self.notations, self.types, self.attributes, self.attribute_groups, self.groups, self.elements) self._builders: Dict[str, Callable[[ElementType, SchemaType], Any]] = { XSD_NOTATION: validator.xsd_notation_class, XSD_SIMPLE_TYPE: validator.simple_type_factory, XSD_COMPLEX_TYPE: validator.xsd_complex_type_class, XSD_ATTRIBUTE: validator.xsd_attribute_class, XSD_ATTRIBUTE_GROUP: validator.xsd_attribute_group_class, XSD_GROUP: validator.xsd_group_class, XSD_ELEMENT: validator.xsd_element_class, } def __repr__(self) -> str: return '%s(validator=%r, validation=%r)' % ( self.__class__.__name__, self.validator, self.validation ) def copy(self, validator: Optional[SchemaType] = None, validation: Optional[str] = None) -> 'XsdGlobals': """Makes a copy of the object.""" obj = self.__class__(self.validator if validator is None else validator, validation or self.validation) obj.namespaces.update(self.namespaces) obj.types.update(self.types) obj.attributes.update(self.attributes) obj.attribute_groups.update(self.attribute_groups) obj.groups.update(self.groups) obj.notations.update(self.notations) obj.elements.update(self.elements) obj.substitution_groups.update(self.substitution_groups) obj.identities.update(self.identities) return obj __copy__ = copy def lookup(self, tag: str, qname: str) -> SchemaGlobalType: """ General lookup method for XSD global components. :param tag: the expanded QName of the XSD the global declaration/definition \ (eg. '{http://www.w3.org/2001/XMLSchema}element'), that is used to select \ the global map for lookup. :param qname: the expanded QName of the component to be looked-up. :returns: an XSD global component. :raises: an XMLSchemaValueError if the *tag* argument is not appropriate for a global \ component, an XMLSchemaKeyError if the *qname* argument is not found in the global map. """ lookup_function: Callable[[str], SchemaGlobalType] try: lookup_function = getattr(self, self._lookup_function_resolver[tag]) except KeyError: msg = "wrong tag {!r} for an XSD global definition/declaration" raise XMLSchemaValueError(msg.format(tag)) from None else: return lookup_function(qname) def lookup_notation(self, qname: str) -> XsdNotation: try: obj = self.notations[qname] except KeyError: raise XMLSchemaKeyError(f'xs:notation {qname!r} not found') else: if isinstance(obj, XsdNotation): return obj return cast(XsdNotation, self._build_global(obj, qname, self.notations)) def lookup_type(self, qname: str) -> BaseXsdType: try: obj = self.types[qname] except KeyError: raise XMLSchemaKeyError(f'global xs:simpleType/xs:complexType {qname!r} not found') else: if isinstance(obj, (XsdSimpleType, XsdComplexType)): return obj return cast(BaseXsdType, self._build_global(obj, qname, self.types)) def lookup_attribute(self, qname: str) -> XsdAttribute: try: obj = self.attributes[qname] except KeyError: raise XMLSchemaKeyError(f'global xs:attribute {qname!r} not found') else: if isinstance(obj, XsdAttribute): return obj return cast(XsdAttribute, self._build_global(obj, qname, self.attributes)) def lookup_attribute_group(self, qname: str) -> XsdAttributeGroup: try: obj = self.attribute_groups[qname] except KeyError: raise XMLSchemaKeyError(f'global xs:attributeGroup {qname!r} not found') else: if isinstance(obj, XsdAttributeGroup): return obj return cast(XsdAttributeGroup, self._build_global(obj, qname, self.attribute_groups)) def lookup_group(self, qname: str) -> XsdGroup: try: obj = self.groups[qname] except KeyError: raise XMLSchemaKeyError(f'global xs:group {qname!r} not found') else: if isinstance(obj, XsdGroup): return obj return cast(XsdGroup, self._build_global(obj, qname, self.groups)) def lookup_element(self, qname: str) -> XsdElement: try: obj = self.elements[qname] except KeyError: raise XMLSchemaKeyError(f'global xs:element {qname!r} not found') else: if isinstance(obj, XsdElement): return obj return cast(XsdElement, self._build_global(obj, qname, self.elements)) def _build_global(self, obj: Any, qname: str, global_map: Dict[str, Any]) -> Any: factory_or_class: Callable[[ElementType, SchemaType], Any] if isinstance(obj, tuple): # Not built XSD global component without redefinitions try: elem, schema = obj except ValueError: return obj[0] # Circular build, simply return (elem, schema) couple try: factory_or_class = self._builders[elem.tag] except KeyError: raise XMLSchemaKeyError("wrong element %r for map %r." % (elem, global_map)) global_map[qname] = obj, # Encapsulate into a tuple to catch circular builds global_map[qname] = factory_or_class(elem, schema) return global_map[qname] elif isinstance(obj, list): # Not built XSD global component with redefinitions try: elem, schema = obj[0] except ValueError: return obj[0][0] # Circular build, simply return (elem, schema) couple try: factory_or_class = self._builders[elem.tag] except KeyError: raise XMLSchemaKeyError("wrong element %r for map %r." % (elem, global_map)) global_map[qname] = obj[0], # To catch circular builds global_map[qname] = component = factory_or_class(elem, schema) # Apply redefinitions (changing elem involve a re-parsing of the component) for elem, schema in obj[1:]: if component.schema.target_namespace != schema.target_namespace: msg = "redefined schema {!r} has a different targetNamespace" raise XMLSchemaValueError(msg.format(schema)) component.redefine = component.copy() component.redefine.parent = component component.schema = schema component.elem = elem return global_map[qname] else: raise XMLSchemaTypeError(f"unexpected instance {obj} in global map") def get_instance_type(self, type_name: str, base_type: BaseXsdType, namespaces: MutableMapping[str, str]) -> BaseXsdType: """ Returns the instance XSI type from global maps, validating it with the reference base type. :param type_name: the XSI type attribute value, a QName in prefixed format. :param base_type: the XSD from which the instance type has to be derived. :param namespaces: a mapping from prefixes to namespaces. """ if isinstance(base_type, XsdComplexType) and XSI_TYPE in base_type.attributes: xsd_attribute = cast(XsdAttribute, base_type.attributes[XSI_TYPE]) xsd_attribute.validate(type_name) extended_name = get_extended_qname(type_name, namespaces) xsi_type = self.lookup_type(extended_name) if xsi_type.is_derived(base_type): return xsi_type elif isinstance(base_type, XsdSimpleType) and \ base_type.is_union() and not base_type.facets: # Can be valid only if the union doesn't have facets, see: # https://www.w3.org/Bugs/Public/show_bug.cgi?id=4065 if isinstance(base_type, XsdAtomicRestriction) and \ isinstance(base_type.primitive_type, XsdUnion): if xsi_type in base_type.primitive_type.member_types: return xsi_type elif isinstance(base_type, XsdUnion): if xsi_type in base_type.member_types: return xsi_type raise XMLSchemaTypeError("%r cannot substitute %r" % (xsi_type, base_type)) @property def built(self) -> bool: return all(schema.built for schema in self.iter_schemas()) @property def unbuilt(self) -> List[Union[XsdComponent, SchemaType]]: """Property that returns a list with unbuilt components.""" return [c for s in self.iter_schemas() for c in s.iter_components() if c is not s and not c.built] @property def validation_attempted(self) -> str: if self.built: return 'full' elif any(schema.validation_attempted == 'partial' for schema in self.iter_schemas()): return 'partial' else: return 'none' @property def validity(self) -> str: if not self.namespaces: return 'notKnown' if all(schema.validity == 'valid' for schema in self.iter_schemas()): return 'valid' elif any(schema.validity == 'invalid' for schema in self.iter_schemas()): return 'invalid' else: return 'notKnown' @property def xsd_version(self) -> str: return self.validator.XSD_VERSION @property def all_errors(self) -> List[XMLSchemaParseError]: errors = [] for schema in self.iter_schemas(): errors.extend(schema.all_errors) return errors def create_bindings(self, *bases: Type[Any], **attrs: Any) -> None: """Creates data object bindings for the XSD elements of built schemas.""" for xsd_element in self.iter_components(xsd_classes=XsdElement): assert isinstance(xsd_element, XsdElement) if xsd_element.target_namespace != XSD_NAMESPACE: xsd_element.get_binding(*bases, replace_existing=True, **attrs) def clear_bindings(self) -> None: for xsd_element in self.iter_components(xsd_classes=XsdElement): assert isinstance(xsd_element, XsdElement) xsd_element.binding = None def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[Union['XsdGlobals', XsdComponent]]: """Creates an iterator for the XSD components of built schemas.""" if xsd_classes is None or isinstance(self, xsd_classes): yield self for xsd_global in self.iter_globals(): yield from xsd_global.iter_components(xsd_classes) def iter_globals(self) -> Iterator[SchemaGlobalType]: """Creates an iterator for the XSD global components of built schemas.""" for global_map in self.global_maps: yield from global_map.values() def iter_schemas(self) -> Iterator[SchemaType]: """Creates an iterator for the registered schemas.""" for schemas in self.namespaces.values(): yield from schemas def register(self, schema: SchemaType) -> None: """Registers an XMLSchema instance.""" try: ns_schemas = self.namespaces[schema.target_namespace] except KeyError: self.namespaces[schema.target_namespace] = [schema] else: if schema in ns_schemas: return elif schema.url is None: # only by multi-source init or add_schema() by user initiative ns_schemas.append(schema) elif not any(schema.url == obj.url and schema.__class__ is obj.__class__ for obj in ns_schemas): ns_schemas.append(schema) @lru_cache(maxsize=1000) def load_namespace(self, namespace: str, build: bool = True) -> bool: """ Load namespace from available location hints. Returns `True` if the namespace is already loaded or if the namespace can be loaded from one of the locations, returns `False` otherwise. Failing locations are inserted into the missing locations list. :param namespace: the namespace to load. :param build: if left with `True` value builds the maps after load. If the \ build fails the resource URL is added to missing locations. """ namespace = namespace.strip() if namespace in self.namespaces: return True elif self.validator.meta_schema is None: return False # Do not load additional namespaces for meta-schema (XHTML) # Try from schemas location hints: usually the namespaces related to these # hints are already loaded during schema construction, but it's better to # retry once if the initial load has failed. for schema in self.iter_schemas(): for url in schema.get_locations(namespace): if url in self.missing_locations: continue try: if schema.import_schema(namespace, url, schema.base_url) is not None: if build: self.build() except (OSError, IOError): pass except XMLSchemaNotBuiltError: self.clear(remove_schemas=True, only_unbuilt=True) self.missing_locations.append(url) else: return True # Try from library location hint, if there is any. if namespace in self.validator.fallback_locations: url = self.validator.fallback_locations[namespace] if url not in self.missing_locations: try: if self.validator.import_schema(namespace, url) is not None: if build: self.build() except (OSError, IOError): return False except XMLSchemaNotBuiltError: self.clear(remove_schemas=True, only_unbuilt=True) self.missing_locations.append(url) else: return True return False def clear(self, remove_schemas: bool = False, only_unbuilt: bool = False) -> None: """ Clears the instance maps and schemas. :param remove_schemas: removes also the schema instances. :param only_unbuilt: removes only not built objects/schemas. """ global_map: Dict[str, XsdComponent] if only_unbuilt: not_built_schemas = {s for s in self.iter_schemas() if not s.built} if not not_built_schemas: return for global_map in self.global_maps: for k in list(global_map.keys()): obj = global_map[k] if not isinstance(obj, XsdComponent) or obj.schema in not_built_schemas: del global_map[k] if k in self.substitution_groups: del self.substitution_groups[k] if k in self.identities: del self.identities[k] if remove_schemas: namespaces = NamespaceResourcesMap() for uri, value in self.namespaces.items(): for schema in value: if schema not in not_built_schemas: namespaces[uri] = schema self.namespaces = namespaces else: del self.missing_locations[:] for global_map in self.global_maps: global_map.clear() self.substitution_groups.clear() self.identities.clear() if remove_schemas: self.namespaces.clear() def build(self) -> None: """ Build the maps of XSD global definitions/declarations. The global maps are updated adding and building the globals of not built registered schemas. """ try: meta_schema = self.namespaces[XSD_NAMESPACE][0] except KeyError: if self.validator.meta_schema is None: msg = "missing XSD namespace in meta-schema instance {!r}" raise XMLSchemaValueError(msg.format(self.validator)) meta_schema = None if meta_schema is None or meta_schema.meta_schema is not None: # XSD namespace not imported or XSD namespace not managed by a meta-schema. # Creates a new meta-schema instance from the XSD meta-schema source and # replaces the default meta-schema instance in all registered schemas. if self.validator.meta_schema is None: msg = "missing default meta-schema instance {!r}" raise XMLSchemaRuntimeError(msg.format(self.validator)) url = self.validator.meta_schema.url base_schemas = {k: v for k, v in self.validator.meta_schema.BASE_SCHEMAS.items() if k not in self.namespaces} meta_schema = self.validator.create_meta_schema(url, base_schemas, self) for schema in self.iter_schemas(): if schema.meta_schema is not None: schema.meta_schema = meta_schema else: if not self.types and meta_schema.maps is not self: for source_map, target_map in zip(meta_schema.maps.global_maps, self.global_maps): target_map.update(source_map) not_built_schemas = [schema for schema in self.iter_schemas() if not schema.built] for schema in not_built_schemas: schema._root_elements = None # Load and build global declarations load_xsd_simple_types(self.types, not_built_schemas) load_xsd_complex_types(self.types, not_built_schemas) load_xsd_notations(self.notations, not_built_schemas) load_xsd_attributes(self.attributes, not_built_schemas) load_xsd_attribute_groups(self.attribute_groups, not_built_schemas) load_xsd_elements(self.elements, not_built_schemas) load_xsd_groups(self.groups, not_built_schemas) if not meta_schema.built: xsd_builtin_types_factory(meta_schema, self.types) if self is not meta_schema.maps: # Rebuild xs:anyType for maps not owned by the meta-schema # in order to do a correct namespace lookup for wildcards. self.types[XSD_ANY_TYPE] = self.validator.create_any_type() for qname in self.notations: self.lookup_notation(qname) for qname in self.attributes: self.lookup_attribute(qname) for qname in self.attribute_groups: self.lookup_attribute_group(qname) for schema in not_built_schemas: if not isinstance(schema.default_attributes, str): continue try: attributes = schema.maps.attribute_groups[schema.default_attributes] except KeyError: schema.default_attributes = None msg = "defaultAttributes={!r} doesn't match an attribute group of {!r}" schema.parse_error( error=msg.format(schema.root.get('defaultAttributes'), schema), elem=schema.root, validation=schema.validation ) else: schema.default_attributes = cast(XsdAttributeGroup, attributes) for qname in self.types: self.lookup_type(qname) for qname in self.elements: self.lookup_element(qname) for qname in self.groups: self.lookup_group(qname) # Build element declarations inside model groups. for schema in not_built_schemas: for group in schema.iter_components(XsdGroup): group.build() # Build identity references and XSD 1.1 assertions for schema in not_built_schemas: for obj in schema.iter_components((XsdIdentity, XsdAssert)): obj.build() self.check(filter(lambda x: x.meta_schema is not None, not_built_schemas), self.validation) def check(self, schemas: Optional[Iterable[SchemaType]] = None, validation: str = 'strict') -> None: """ Checks the global maps. For default checks all schemas and raises an exception at first error. :param schemas: optional argument with the set of the schemas to check. :param validation: overrides the default validation mode of the validator. :raise: XMLSchemaParseError """ _schemas = set(schemas if schemas is not None else self.iter_schemas()) # Checks substitution groups circularity for qname in self.substitution_groups: xsd_element = self.elements[qname] assert isinstance(xsd_element, XsdElement), "global element not built!" if any(e is xsd_element for e in xsd_element.iter_substitutes()): msg = "circularity found for substitution group with head element %r" xsd_element.parse_error(msg.format(xsd_element), validation=validation) if validation == 'strict' and not self.built: raise XMLSchemaNotBuiltError( self, "global map has unbuilt components: %r" % self.unbuilt ) # Check redefined global groups restrictions for group in self.groups.values(): assert isinstance(group, XsdGroup), "global group not built!" if group.schema not in _schemas or group.redefine is None: continue while group.redefine is not None: if not any(isinstance(e, XsdGroup) and e.name == group.name for e in group) \ and not group.is_restriction(group.redefine): msg = "the redefined group is an illegal restriction of the original group" group.parse_error(msg, validation=validation) group = group.redefine # Check complex content types models restrictions for xsd_global in filter(lambda x: x.schema in _schemas, self.iter_globals()): xsd_type: Any for xsd_type in xsd_global.iter_components(XsdComplexType): if not isinstance(xsd_type.content, XsdGroup): continue if xsd_type.derivation == 'restriction': base_type = xsd_type.base_type if base_type and base_type.name != XSD_ANY_TYPE and base_type.is_complex(): if not xsd_type.content.is_restriction(base_type.content): xsd_type.parse_error("the derived group is an illegal restriction " "of the base type group", validation=validation) if base_type.is_complex() and not base_type.open_content and \ xsd_type.open_content and xsd_type.open_content.mode != 'none': _group = xsd_type.schema.create_any_content_group( parent=xsd_type, any_element=xsd_type.open_content.any_element ) if not _group.is_restriction(base_type.content): msg = "restriction has an open content but base type has not" _group.parse_error(msg, validation=validation) try: xsd_type.content.check_model() except XMLSchemaModelDepthError: msg = "cannot verify the content model of {!r} " \ "due to maximum recursion depth exceeded".format(xsd_type) xsd_type.schema.warnings.append(msg) warnings.warn(msg, XMLSchemaWarning, stacklevel=4) except XMLSchemaModelError as err: if validation == 'strict': raise xsd_type.errors.append(err) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/groups.py�����������������������������������������������������0000664�0000000�0000000�00000174733�14211403446�0021612�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for XML Schema model groups. """ import warnings from collections.abc import MutableMapping from typing import TYPE_CHECKING, overload, Any, Iterable, Iterator, List, \ MutableSequence, Optional, Tuple, Union from .. import limits from ..exceptions import XMLSchemaValueError from ..names import XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE, XSD_ELEMENT, \ XSD_ANY, XSI_TYPE, XSD_ANY_TYPE, XSD_ANNOTATION from ..etree import etree_element, ElementData from ..aliases import ElementType, NamespacesType, SchemaType, IterDecodeType, \ IterEncodeType, ModelParticleType, SchemaElementType, ComponentClassType from ..helpers import get_qname, local_name, raw_xml_encode from .exceptions import XMLSchemaModelError, XMLSchemaModelDepthError, \ XMLSchemaValidationError, XMLSchemaChildrenValidationError, \ XMLSchemaTypeTableWarning from .xsdbase import ValidationMixin, XsdComponent, XsdType from .particles import ParticleMixin, OccursCalculator from .elements import XsdElement, XsdAlternative from .wildcards import XsdAnyElement, Xsd11AnyElement from .models import ModelVisitor, distinguishable_paths if TYPE_CHECKING: from .complex_types import XsdComplexType ANY_ELEMENT = etree_element( XSD_ANY, attrib={ 'namespace': '##any', 'processContents': 'lax', 'minOccurs': '0', 'maxOccurs': 'unbounded' }) GroupDecodeType = List[Tuple[Union[str, int], Any, Optional[SchemaElementType]]] GroupEncodeType = Tuple[Optional[str], List[ElementType]] class XsdGroup(XsdComponent, MutableSequence[ModelParticleType], ParticleMixin, ValidationMixin[ElementType, GroupDecodeType]): """ Class for XSD 1.0 *model group* definitions. .. <group id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 name = NCName ref = QName {any attributes with non-schema namespace . . .}> Content: (annotation?, (all | choice | sequence)?) </group> .. <all id = ID maxOccurs = 1 : 1 minOccurs = (0 | 1) : 1 {any attributes with non-schema namespace . . .}> Content: (annotation?, element*) </all> .. <choice id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 {any attributes with non-schema namespace . . .}> Content: (annotation?, (element | group | choice | sequence | any)*) </choice> .. <sequence id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 {any attributes with non-schema namespace . . .}> Content: (annotation?, (element | group | choice | sequence | any)*) </sequence> """ parent: Optional[Union['XsdComplexType', 'XsdGroup']] model: str mixed: bool = False ref: Optional['XsdGroup'] restriction: Optional['XsdGroup'] = None # For XSD 1.1 openContent processing interleave: Optional[Xsd11AnyElement] = None # if openContent with mode='interleave' suffix: Optional[Xsd11AnyElement] = None # if openContent with mode='suffix'/'interleave' _ADMITTED_TAGS = {XSD_GROUP, XSD_SEQUENCE, XSD_ALL, XSD_CHOICE} def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[Union['XsdComplexType', 'XsdGroup']] = None) -> None: self._group: List[ModelParticleType] = [] if parent is not None and parent.mixed: self.mixed = parent.mixed super(XsdGroup, self).__init__(elem, schema, parent) def __repr__(self) -> str: if self.name is None: return '%s(model=%r, occurs=%r)' % ( self.__class__.__name__, self.model, list(self.occurs) ) elif self.ref is None: return '%s(name=%r, model=%r, occurs=%r)' % ( self.__class__.__name__, self.prefixed_name, self.model, list(self.occurs) ) else: return '%s(ref=%r, model=%r, occurs=%r)' % ( self.__class__.__name__, self.prefixed_name, self.model, list(self.occurs) ) @overload def __getitem__(self, i: int) -> ModelParticleType: ... @overload def __getitem__(self, s: slice) -> MutableSequence[ModelParticleType]: ... def __getitem__(self, i: Union[int, slice]) \ -> Union[ModelParticleType, MutableSequence[ModelParticleType]]: return self._group[i] def __setitem__(self, i: Union[int, slice], o: Any) -> None: self._group[i] = o def __delitem__(self, i: Union[int, slice]) -> None: del self._group[i] def __len__(self) -> int: return len(self._group) def insert(self, i: int, item: ModelParticleType) -> None: self._group.insert(i, item) def clear(self) -> None: del self._group[:] def is_emptiable(self) -> bool: if self.model == 'choice': return self.min_occurs == 0 or not self or any(item.is_emptiable() for item in self) else: return self.min_occurs == 0 or not self or all(item.is_emptiable() for item in self) def is_single(self) -> bool: if self.max_occurs != 1 or not self: return False elif len(self) > 1 or not isinstance(self[0], XsdGroup): return True else: return self[0].is_single() def is_pointless(self, parent: 'XsdGroup') -> bool: """ Returns `True` if the group may be eliminated without affecting the model, `False` otherwise. A group is pointless if one of those conditions is verified: - the group is empty - minOccurs == maxOccurs == 1 and the group has one child - minOccurs == maxOccurs == 1 and the group and its parent have a sequence model - minOccurs == maxOccurs == 1 and the group and its parent have a choice model Ref: https://www.w3.org/TR/2004/REC-xmlschema-1-20041028/#coss-particle :param parent: effective parent of the model group. """ if not self: return True elif self.min_occurs != 1 or self.max_occurs != 1: return False elif len(self) == 1: return True elif self.model == 'sequence' and parent.model != 'sequence': return False elif self.model == 'choice' and parent.model != 'choice': return False else: return True @property def effective_min_occurs(self) -> int: if not self.min_occurs or not self: return 0 elif self.model == 'choice': if any(not e.effective_min_occurs for e in self.iter_model()): return 0 else: if all(not e.effective_min_occurs for e in self.iter_model()): return 0 return self.min_occurs @property def effective_max_occurs(self) -> Optional[int]: if self.max_occurs == 0 or not self: return 0 effective_items: List[Any] value: int effective_items = [e for e in self.iter_model() if e.effective_max_occurs != 0] if not effective_items: return 0 elif self.max_occurs is None: return None elif self.model == 'choice': try: value = max(e.effective_max_occurs for e in effective_items) except TypeError: return None else: return self.max_occurs * value not_emptiable_items = [e for e in effective_items if e.effective_min_occurs] if not not_emptiable_items: try: value = max(e.effective_max_occurs for e in effective_items) except TypeError: return None else: return self.max_occurs * value elif len(not_emptiable_items) > 1: return self.max_occurs value = not_emptiable_items[0].effective_max_occurs return None if value is None else self.max_occurs * value def has_occurs_restriction( self, other: Union[ModelParticleType, ParticleMixin, 'OccursCalculator']) -> bool: if not self: return True elif isinstance(other, XsdGroup): return super(XsdGroup, self).has_occurs_restriction(other) # Group particle compared to element particle if self.max_occurs is None or any(e.max_occurs is None for e in self): if other.max_occurs is not None: return False elif self.model == 'choice': return self.min_occurs * min(e.min_occurs for e in self) >= other.min_occurs else: return self.min_occurs * sum(e.min_occurs for e in self) >= other.min_occurs elif self.model == 'choice': if self.min_occurs * min(e.min_occurs for e in self) < other.min_occurs: return False elif other.max_occurs is None: return True else: value: int try: value = max(e.max_occurs for e in self) # type: ignore[type-var, assignment] except TypeError: return False else: return self.max_occurs * value <= other.max_occurs else: if self.min_occurs * sum(e.min_occurs for e in self) < other.min_occurs: return False elif other.max_occurs is None: return True else: try: value = sum(e.max_occurs for e in self) # type: ignore[misc] except TypeError: return False else: return self.max_occurs * value <= other.max_occurs def iter_model(self) -> Iterator[ModelParticleType]: """ A generator function iterating elements and groups of a model group. Skips pointless groups, iterating deeper through them. Raises `XMLSchemaModelDepthError` if the *depth* of the model is over `limits.MAX_MODEL_DEPTH` value. """ iterators: List[Iterator[ModelParticleType]] = [] particles = iter(self) while True: try: item = next(particles) except StopIteration: try: particles = iterators.pop() except IndexError: return else: if isinstance(item, XsdGroup) and item.is_pointless(parent=self): iterators.append(particles) particles = iter(item) if len(iterators) > limits.MAX_MODEL_DEPTH: raise XMLSchemaModelDepthError(self) else: yield item def iter_elements(self) -> Iterator[SchemaElementType]: """ A generator function iterating model's elements. Raises `XMLSchemaModelDepthError` if the overall depth of the model groups is over `limits.MAX_MODEL_DEPTH`. """ if self.max_occurs == 0: return iterators: List[Iterator[ModelParticleType]] = [] particles = iter(self) while True: try: item = next(particles) except StopIteration: try: particles = iterators.pop() except IndexError: return else: if isinstance(item, XsdGroup): iterators.append(particles) particles = iter(item) if len(iterators) > limits.MAX_MODEL_DEPTH: raise XMLSchemaModelDepthError(self) else: yield item def get_subgroups(self, item: ModelParticleType) -> List['XsdGroup']: """ Returns a list of the groups that represent the path to the enclosed particle. Raises an `XMLSchemaModelError` if *item* is not a particle of the model group. """ subgroups: List[Tuple[XsdGroup, Iterator[ModelParticleType]]] = [] group, children = self, iter(self) while True: try: child = next(children) except StopIteration: try: group, children = subgroups.pop() except IndexError: msg = '{!r} is not a particle of the model group' raise XMLSchemaModelError(self, msg.format(item)) from None else: continue if child is item: _subgroups = [x[0] for x in subgroups] _subgroups.append(group) return _subgroups elif isinstance(child, XsdGroup): if len(subgroups) > limits.MAX_MODEL_DEPTH: raise XMLSchemaModelDepthError(self) subgroups.append((group, children)) group, children = child, iter(child) def overall_min_occurs(self, item: ModelParticleType) -> int: """Returns the overall min occurs of a particle in the model.""" min_occurs = item.min_occurs for group in self.get_subgroups(item): if group.model == 'choice' and len(group) > 1: return 0 min_occurs *= group.min_occurs return min_occurs def overall_max_occurs(self, item: ModelParticleType) -> Optional[int]: """Returns the overall max occurs of a particle in the model.""" max_occurs = item.max_occurs for group in self.get_subgroups(item): if max_occurs == 0: return 0 elif max_occurs is None: continue elif group.max_occurs is None: max_occurs = None else: max_occurs *= group.max_occurs return max_occurs def copy(self) -> 'XsdGroup': group: XsdGroup = object.__new__(self.__class__) group.__dict__.update(self.__dict__) group.errors = self.errors[:] group._group = self._group[:] return group __copy__ = copy def _parse(self) -> None: self.clear() self._parse_particle(self.elem) if self.elem.tag != XSD_GROUP: # Local group (sequence|all|choice) if 'name' in self.elem.attrib: self.parse_error("attribute 'name' not allowed for a local group") self._parse_content_model(self.elem) elif self._parse_reference(): assert self.name is not None try: xsd_group = self.maps.lookup_group(self.name) except KeyError: self.parse_error("missing group %r" % self.prefixed_name) xsd_group = self.schema.create_any_content_group(parent=self) if isinstance(xsd_group, XsdGroup): self.model = xsd_group.model if self.model == 'all': if self.max_occurs != 1: self.parse_error("maxOccurs must be 1 for 'all' model groups") if self.min_occurs not in (0, 1): self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") if self.xsd_version == '1.0' and isinstance(self.parent, XsdGroup): self.parse_error("in XSD 1.0 the 'all' model group cannot be nested") self._group.append(xsd_group) self.ref = xsd_group else: # Disallowed circular definition, substitute with any content group. self.parse_error("Circular definitions detected for group %r:" % self.name, xsd_group[0]) self.model = 'sequence' self.mixed = True self._group.append(self.schema.xsd_any_class(ANY_ELEMENT, self.schema, self)) else: attrib = self.elem.attrib try: self.name = get_qname(self.target_namespace, attrib['name']) except KeyError: pass else: if self.parent is not None: self.parse_error("attribute 'name' not allowed for a local group") else: if 'minOccurs' in attrib: self.parse_error("attribute 'minOccurs' not allowed for a global group") if 'maxOccurs' in attrib: self.parse_error("attribute 'maxOccurs' not allowed for a global group") content_model = self._parse_child_component(self.elem, strict=True) if content_model is not None: if self.parent is None: if 'minOccurs' in content_model.attrib: self.parse_error("attribute 'minOccurs' not allowed for the model " "of a global group", content_model) if 'maxOccurs' in content_model.attrib: self.parse_error("attribute 'maxOccurs' not allowed for the model " "of a global group", content_model) if content_model.tag in {XSD_SEQUENCE, XSD_ALL, XSD_CHOICE}: self._parse_content_model(content_model) else: self.parse_error('unexpected tag %r' % content_model.tag, content_model) def _parse_content_model(self, content_model: ElementType) -> None: self.model = local_name(content_model.tag) if self.model == 'all': if self.max_occurs != 1: self.parse_error("maxOccurs must be 1 for 'all' model groups") if self.min_occurs not in (0, 1): self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") child: ElementType for child in content_model: if child.tag == XSD_ANNOTATION or callable(child.tag): continue elif child.tag == XSD_ELEMENT: # Builds inner elements later, for avoid circularity. self.append(self.schema.xsd_element_class(child, self.schema, self, False)) elif content_model.tag == XSD_ALL: self.parse_error("'all' model can contains only elements.") elif child.tag == XSD_ANY: self._group.append(XsdAnyElement(child, self.schema, self)) elif child.tag in (XSD_SEQUENCE, XSD_CHOICE): self._group.append(XsdGroup(child, self.schema, self)) elif child.tag == XSD_GROUP: try: ref = self.schema.resolve_qname(child.attrib['ref']) except (KeyError, ValueError, RuntimeError) as err: if 'ref' not in child.attrib: self.parse_error("missing attribute 'ref' in local group", child) else: self.parse_error(err, child) continue if ref != self.name: xsd_group = XsdGroup(child, self.schema, self) if xsd_group.model == 'all': self.parse_error("'all' model can appears only at 1st level " "of a model group") else: self._group.append(xsd_group) elif self.redefine is None: self.parse_error("Circular definition detected for group %r:" % self.name) else: if child.get('minOccurs', '1') != '1' or child.get('maxOccurs', '1') != '1': self.parse_error("Redefined group reference cannot have " "minOccurs/maxOccurs other than 1:") self._group.append(self.redefine) def build(self) -> None: for item in self._group: if isinstance(item, XsdElement): item.build() if self.redefine is not None: for group in self.redefine.iter_components(XsdGroup): group.build() @property def built(self) -> bool: for item in self: if isinstance(item, XsdElement): if not item.built: return False elif isinstance(item, XsdAnyElement): continue elif item.parent is None: continue elif item.parent is not self.parent and \ isinstance(item.parent, XsdType) and item.parent.parent is None: continue elif not item.ref and not item.built: return False return True if self.model else False @property def validation_attempted(self) -> str: if self.built: return 'full' elif any(item.validation_attempted == 'partial' for item in self): return 'partial' else: return 'none' @property def schema_elem(self) -> ElementType: return self.parent.elem if self.parent is not None else self.elem def iter_components(self, xsd_classes: Optional[ComponentClassType] = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self for item in self: if item.parent is None: continue elif item.parent is not self.parent and isinstance(item.parent, XsdType) \ and item.parent.parent is None: continue yield from item.iter_components(xsd_classes) if self.redefine is not None and self.redefine not in self: yield from self.redefine.iter_components(xsd_classes) def admits_restriction(self, model: str) -> bool: if self.model == model: return True elif self.model == 'all': return model == 'sequence' elif self.model == 'choice': return model == 'sequence' or len(self.ref or self) <= 1 else: return model == 'choice' or len(self.ref or self) <= 1 def is_empty(self) -> bool: return not self.mixed and (not self._group or self.max_occurs == 0) def is_restriction(self, other: ModelParticleType, check_occurs: bool = True) -> bool: if not self._group: return True elif not isinstance(other, ParticleMixin): raise XMLSchemaValueError("the argument 'other' must be an XSD particle") elif not isinstance(other, XsdGroup): return self.is_element_restriction(other) elif not other: return False elif len(other) == other.min_occurs == other.max_occurs == 1: if len(self) > 1: return self.is_restriction(other[0], check_occurs) elif self.ref is None and isinstance(self[0], XsdGroup) \ and self[0].is_pointless(parent=self): return self[0].is_restriction(other[0], check_occurs) # Compare model with model if self.model != other.model and self.model != 'sequence' and \ (len(self) > 1 or self.ref is not None and len(self[0]) > 1): return False elif self.model == other.model or other.model == 'sequence': return self.is_sequence_restriction(other) elif other.model == 'all': return self.is_all_restriction(other) else: # other.model == 'choice': return self.is_choice_restriction(other) def is_element_restriction(self, other: ModelParticleType) -> bool: if self.xsd_version == '1.0' and isinstance(other, XsdElement) and \ not other.ref and other.name not in self.schema.substitution_groups: return False elif not self.has_occurs_restriction(other): return False elif self.model == 'choice': if other.name in self.maps.substitution_groups and \ all(isinstance(e, XsdElement) and e.substitution_group == other.name for e in self): return True return any(e.is_restriction(other, False) for e in self) else: min_occurs = 0 max_occurs: Optional[int] = 0 for item in self.iter_model(): if isinstance(item, XsdGroup): return False elif item.min_occurs == 0 or item.is_restriction(other, False): min_occurs += item.min_occurs if max_occurs is not None: if item.max_occurs is None: max_occurs = None else: max_occurs += item.max_occurs continue return False if min_occurs < other.min_occurs: return False elif max_occurs is None: return other.max_occurs is None elif other.max_occurs is None: return True else: return max_occurs <= other.max_occurs def is_sequence_restriction(self, other: 'XsdGroup') -> bool: if not self.has_occurs_restriction(other): return False check_occurs = other.max_occurs != 0 # Same model: declarations must simply preserve order other_iterator = iter(other.iter_model()) for item in self.iter_model(): while True: try: other_item = next(other_iterator) except StopIteration: return False if other_item is item or item.is_restriction(other_item, check_occurs): break elif other.model == 'choice': if item.max_occurs != 0: continue elif not other_item.is_matching(item.name, self.default_namespace): continue elif all(e.max_occurs == 0 for e in self.iter_model()): return False else: break elif not other_item.is_emptiable(): return False if other.model == 'choice': return True while True: try: other_item = next(other_iterator) except StopIteration: return True else: if not other_item.is_emptiable(): return False def is_all_restriction(self, other: 'XsdGroup') -> bool: if not self.has_occurs_restriction(other): return False check_occurs = other.max_occurs != 0 if self.ref is None: restriction_items = [x for x in self] else: restriction_items = [x for x in self[0]] for other_item in other.iter_model(): for item in restriction_items: if other_item is item or item.is_restriction(other_item, check_occurs): break else: if not other_item.is_emptiable(): return False continue restriction_items.remove(item) return not bool(restriction_items) def is_choice_restriction(self, other: 'XsdGroup') -> bool: if self.ref is None: if self.parent is None and other.parent is not None: return False # not allowed restriction in XSD 1.0 restriction_items = [x for x in self] elif other.parent is None: restriction_items = [x for x in self[0]] else: return False # not allowed restriction in XSD 1.0 check_occurs = other.max_occurs != 0 max_occurs: Optional[int] = 0 other_max_occurs: Optional[int] = 0 for other_item in other.iter_model(): for item in restriction_items: if other_item is item or item.is_restriction(other_item, check_occurs): if max_occurs is not None: if item.max_occurs is None: max_occurs = None else: max_occurs += item.max_occurs if other_max_occurs is not None: if other_item.max_occurs is None: other_max_occurs = None else: other_max_occurs = max(other_max_occurs, other_item.max_occurs) break else: continue restriction_items.remove(item) if restriction_items: return False elif other_max_occurs is None: if other.max_occurs != 0: return True other_max_occurs = 0 elif other.max_occurs is None: if other_max_occurs != 0: return True other_max_occurs = 0 else: other_max_occurs *= other.max_occurs if max_occurs is None: return self.max_occurs == 0 elif self.max_occurs is None: return max_occurs == 0 else: return other_max_occurs >= max_occurs * self.max_occurs def check_model(self) -> None: """ Checks if the model group is deterministic. Element Declarations Consistent and Unique Particle Attribution constraints are checked. :raises: an `XMLSchemaModelError` at first violated constraint. """ def safe_iter_path() -> Iterator[SchemaElementType]: iterators: List[Iterator[ModelParticleType]] = [] particles = iter(self) while True: try: item = next(particles) except StopIteration: try: current_path.pop() particles = iterators.pop() except IndexError: return else: if isinstance(item, XsdGroup): current_path.append(item) iterators.append(particles) particles = iter(item) if len(iterators) > limits.MAX_MODEL_DEPTH: raise XMLSchemaModelDepthError(self) else: yield item paths: Any = {} current_path: List[ModelParticleType] = [self] try: any_element = self.parent.open_content.any_element # type: ignore[union-attr] except AttributeError: any_element = None for e in safe_iter_path(): previous_path: List[ModelParticleType] for pe, previous_path in paths.values(): # EDC check if not e.is_consistent(pe) or any_element and not any_element.is_consistent(pe): msg = "Element Declarations Consistent violation between %r and %r: " \ "match the same name but with different types" % (e, pe) raise XMLSchemaModelError(self, msg) # UPA check if pe is e or not pe.is_overlap(e): continue elif pe.parent is e.parent: if pe.parent.model in {'all', 'choice'}: if isinstance(pe, Xsd11AnyElement) and not isinstance(e, XsdAnyElement): pe.add_precedence(e, self) elif isinstance(e, Xsd11AnyElement) and not isinstance(pe, XsdAnyElement): e.add_precedence(pe, self) else: msg = "{!r} and {!r} overlap and are in the same {!r} group" raise XMLSchemaModelError(self, msg.format(pe, e, pe.parent.model)) elif pe.min_occurs == pe.max_occurs: continue if distinguishable_paths(previous_path + [pe], current_path + [e]): continue elif isinstance(pe, Xsd11AnyElement) and not isinstance(e, XsdAnyElement): pe.add_precedence(e, self) elif isinstance(e, Xsd11AnyElement) and not isinstance(pe, XsdAnyElement): e.add_precedence(pe, self) else: msg = "Unique Particle Attribution violation between {!r} and {!r}" raise XMLSchemaModelError(self, msg.format(pe, e)) paths[e.name] = e, current_path[:] def check_dynamic_context(self, elem: ElementType, xsd_element: SchemaElementType, model_element: SchemaElementType, namespaces: NamespacesType) -> None: if model_element is not xsd_element and isinstance(model_element, XsdElement): if 'substitution' in model_element.block \ or xsd_element.type and xsd_element.type.is_blocked(model_element): raise XMLSchemaValidationError( model_element, elem, "substitution of %r is blocked" % model_element ) alternatives: Union[Tuple[()], List[XsdAlternative]] = [] if isinstance(xsd_element, XsdAnyElement): if xsd_element.process_contents == 'skip': return try: xsd_element = self.maps.lookup_element(elem.tag) except LookupError: try: type_name = elem.attrib[XSI_TYPE].strip() except KeyError: return else: xsd_type = self.maps.get_instance_type( type_name, self.any_type, namespaces ) else: alternatives = xsd_element.alternatives try: type_name = elem.attrib[XSI_TYPE].strip() except KeyError: xsd_type = xsd_element.type else: xsd_type = self.maps.get_instance_type( type_name, xsd_element.type, namespaces ) else: if XSI_TYPE not in elem.attrib: xsd_type = xsd_element.type else: alternatives = xsd_element.alternatives try: type_name = elem.attrib[XSI_TYPE].strip() except KeyError: xsd_type = xsd_element.type else: xsd_type = self.maps.get_instance_type( type_name, xsd_element.type, namespaces ) if model_element is not xsd_element and \ isinstance(model_element, XsdElement) and model_element.block: for derivation in model_element.block.split(): if xsd_type is not model_element.type and \ xsd_type.is_derived(model_element.type, derivation): reason = "usage of %r with type %s is blocked by head element" raise XMLSchemaValidationError( self, elem, reason % (xsd_element, derivation) ) if XSI_TYPE not in elem.attrib: return # If it's a restriction the context is the base_type's group group = self.restriction if self.restriction is not None else self # Dynamic EDC check of matched element for e in group.iter_elements(): if not isinstance(e, XsdElement): continue elif e.name == elem.tag: other = e else: for other in e.iter_substitutes(): if other.name == elem.tag: break else: continue if len(other.alternatives) != len(alternatives) or \ not xsd_type.is_dynamic_consistent(other.type): reason = "%r that matches %r is not consistent with local declaration %r" raise XMLSchemaValidationError(self, reason % (elem, xsd_element, other)) if not all(any(a == x for x in alternatives) for a in other.alternatives) or \ not all(any(a == x for x in other.alternatives) for a in alternatives): msg = "Maybe a not equivalent type table between elements %r and %r." warnings.warn(msg % (self, xsd_element), XMLSchemaTypeTableWarning, stacklevel=3) def match_element(self, name: str, default_namespace: Optional[str] = None) \ -> Optional[SchemaElementType]: """ Try a model-less match of a child element. Returns the matched element, or `None` if there is no match. """ for xsd_element in self.iter_elements(): if xsd_element.is_matching(name, default_namespace, group=self): return xsd_element return None def iter_decode(self, obj: ElementType, validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[GroupDecodeType]: """ Creates an iterator for decoding an Element content. :param obj: an Element. :param validation: the validation mode, can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the decoding process. :return: yields a list of 3-tuples (key, decoded data, decoder), \ eventually preceded by a sequence of validation or decoding errors. """ result_list: GroupDecodeType = [] cdata_index = 1 # keys for CDATA sections are positive integers if not self._group and self.model == 'choice' and self.min_occurs: reason = "an empty 'choice' group with minOccurs > 0 cannot validate any content" yield self.validation_error(validation, reason, obj, **kwargs) yield result_list return if not self.mixed: # Check element CDATA if obj.text and obj.text.strip() or \ any(child.tail and child.tail.strip() for child in obj): if len(self) == 1 and isinstance(self[0], XsdAnyElement): pass # [XsdAnyElement()] equals to an empty complexType declaration else: reason = "character data between child elements not allowed" yield self.validation_error(validation, reason, obj, **kwargs) cdata_index = 0 # Do not decode CDATA if cdata_index and obj.text is not None: text = str(obj.text.strip()) if text: result_list.append((cdata_index, text, None)) cdata_index += 1 level = kwargs['level'] = kwargs.pop('level', 0) + 1 over_max_depth = 'max_depth' in kwargs and kwargs['max_depth'] <= level if level > limits.MAX_XML_DEPTH: reason = "XML data depth exceeded (MAX_XML_DEPTH=%r)" % limits.MAX_XML_DEPTH self.validation_error('strict', reason, obj, **kwargs) try: namespaces = kwargs['namespaces'] except KeyError: namespaces = default_namespace = None else: try: default_namespace = namespaces.get('') except AttributeError: default_namespace = None errors: List[Tuple[int, ModelParticleType, int, Optional[List[SchemaElementType]]]] xsd_element: Optional[SchemaElementType] expected: Optional[List[SchemaElementType]] model = ModelVisitor(self) errors = [] broken_model = False for index, child in enumerate(obj): if callable(child.tag): continue # child is a <class 'lxml.etree._Comment'> while model.element is not None: xsd_element = model.element.match( child.tag, default_namespace, group=self, occurs=model.occurs ) if xsd_element is None: if self.interleave is not None and self.interleave.is_matching( child.tag, default_namespace, self, model.occurs): xsd_element = self.interleave break for particle, occurs, expected in model.advance(False): errors.append((index, particle, occurs, expected)) model.clear() broken_model = True # the model is broken, continues with raw decoding. xsd_element = self.match_element(child.tag, default_namespace) break else: continue break try: self.check_dynamic_context(child, xsd_element, model.element, namespaces) except XMLSchemaValidationError as err: yield self.validation_error(validation, err, obj, **kwargs) for particle, occurs, expected in model.advance(True): errors.append((index, particle, occurs, expected)) break else: if self.suffix is not None and \ self.suffix.is_matching(child.tag, default_namespace, self): xsd_element = self.suffix else: xsd_element = self.match_element(child.tag, default_namespace) if xsd_element is None: errors.append((index, self, 0, None)) broken_model = True elif not broken_model: errors.append((index, xsd_element, 0, [])) broken_model = True if xsd_element is None: if kwargs.get('keep_unknown') and 'converter' in kwargs: for result in self.any_type.iter_decode(child, validation, **kwargs): result_list.append((child.tag, result, None)) continue elif 'converter' not in kwargs: # Validation-only mode: do not append results for result in xsd_element.iter_decode(child, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result continue elif over_max_depth: if 'depth_filler' in kwargs: func = kwargs['depth_filler'] result_list.append((child.tag, func(xsd_element), xsd_element)) continue for result in xsd_element.iter_decode(child, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: result_list.append((child.tag, result, xsd_element)) if cdata_index and child.tail is not None: tail = str(child.tail.strip()) if tail: if result_list and isinstance(result_list[-1][0], int): tail = result_list[-1][1] + ' ' + tail result_list[-1] = result_list[-1][0], tail, None else: result_list.append((cdata_index, tail, None)) cdata_index += 1 if model.element is not None: index = len(obj) for particle, occurs, expected in model.stop(): errors.append((index, particle, occurs, expected)) if errors: source = kwargs.get('source') for index, particle, occurs, expected in errors: error = XMLSchemaChildrenValidationError( self, obj, index, particle, occurs, expected, source, namespaces ) if validation == 'strict': raise error yield error yield result_list def iter_encode(self, obj: ElementData, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[GroupEncodeType]: """ Creates an iterator for encoding data to a list containing Element data. :param obj: an ElementData instance. :param validation: the validation mode: can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the encoding process. :return: yields a couple with the text of the Element and a list of child \ elements, eventually preceded by a sequence of validation errors. """ level = kwargs['level'] = kwargs.get('level', 0) + 1 errors = [] text = raw_xml_encode(obj.text) children: List[ElementType] = [] try: indent = kwargs['indent'] except KeyError: indent = 4 padding = '\n' + ' ' * indent * level try: converter = kwargs['converter'] except KeyError: converter = kwargs['converter'] = self.schema.get_converter(**kwargs) default_namespace = converter.get('') model = ModelVisitor(self) index = cdata_index = 0 wrong_content_type = False over_max_depth = 'max_depth' in kwargs and kwargs['max_depth'] <= level content: Iterable[Any] if obj.content is None: content = [] elif isinstance(obj.content, MutableMapping) or kwargs.get('unordered'): content = ModelVisitor(self).iter_unordered_content( obj.content, default_namespace ) elif not isinstance(obj.content, MutableSequence): wrong_content_type = True content = [] elif converter.losslessly: content = obj.content else: content = ModelVisitor(self).iter_collapsed_content( obj.content, default_namespace ) for index, (name, value) in enumerate(content): if isinstance(name, int): if not children: text = padding + value if text is None else text + value + padding elif children[-1].tail is None: children[-1].tail = padding + value else: children[-1].tail += value + padding cdata_index += 1 continue xsd_element: Optional[SchemaElementType] if self.interleave and self.interleave.is_matching(name, default_namespace, group=self): xsd_element = self.interleave value = get_qname(default_namespace, name), value else: while model.element is not None: xsd_element = model.element.match( name, default_namespace, group=self, occurs=model.occurs ) if xsd_element is None: for particle, occurs, expected in model.advance(): errors.append((index - cdata_index, particle, occurs, expected)) continue elif isinstance(xsd_element, XsdAnyElement): value = get_qname(default_namespace, name), value for particle, occurs, expected in model.advance(True): errors.append((index - cdata_index, particle, occurs, expected)) break else: if self.suffix and self.suffix.is_matching(name, default_namespace, group=self): xsd_element = self.suffix value = get_qname(default_namespace, name), value else: errors.append((index - cdata_index, self, 0, [])) xsd_element = self.match_element(name, default_namespace) if isinstance(xsd_element, XsdAnyElement): value = get_qname(default_namespace, name), value elif xsd_element is None: if name.startswith('{') or ':' not in name: reason = '{!r} does not match any declared element ' \ 'of the model group.'.format(name) else: reason = '{} has an unknown prefix {!r}'.format( name, name.split(':')[0] ) yield self.validation_error(validation, reason, value, **kwargs) continue if over_max_depth: continue for result in xsd_element.iter_encode(value, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: children.append(result) if model.element is not None: for particle, occurs, expected in model.stop(): errors.append((index - cdata_index + 1, particle, occurs, expected)) if children: if children[-1].tail is None: children[-1].tail = padding[:-indent] or '\n' else: children[-1].tail = children[-1].tail.strip() + (padding[:-indent] or '\n') cdata_not_allowed = not self.mixed and text and text.strip() and self and \ (len(self) > 1 or not isinstance(self[0], XsdAnyElement)) if errors or cdata_not_allowed or wrong_content_type: attrib = {k: raw_xml_encode(v) for k, v in obj.attributes.items()} elem = converter.etree_element(obj.tag, text, children, attrib) if wrong_content_type: reason = "wrong content type {!r}".format(type(obj.content)) yield self.validation_error(validation, reason, elem, **kwargs) if cdata_not_allowed: reason = "character data between child elements not allowed" yield self.validation_error(validation, reason, elem, **kwargs) for index, particle, occurs, expected in errors: error = XMLSchemaChildrenValidationError( validator=self, elem=elem, index=index, particle=particle, occurs=occurs, expected=expected, namespaces=converter.namespaces, ) if validation == 'strict': raise error error.elem = None # replace with the element of the encoded tree yield error yield text, children class Xsd11Group(XsdGroup): """ Class for XSD 1.1 *model group* definitions. .. The XSD 1.1 model groups differ from XSD 1.0 groups for the 'all' model, .. that can contains also other groups. .. <all id = ID maxOccurs = (0 | 1) : 1 minOccurs = (0 | 1) : 1 {any attributes with non-schema namespace . . .}> Content: (annotation?, (element | any | group)*) </all> """ def _parse_content_model(self, content_model: ElementType) -> None: self.model = local_name(content_model.tag) if self.model == 'all': if self.max_occurs not in (0, 1): self.parse_error("maxOccurs must be (0 | 1) for 'all' model groups") if self.min_occurs not in (0, 1): self.parse_error("minOccurs must be (0 | 1) for 'all' model groups") for child in content_model: if child.tag == XSD_ELEMENT: # Builds inner elements later, for avoid circularity. self.append(self.schema.xsd_element_class(child, self.schema, self, False)) elif child.tag == XSD_ANY: self._group.append(Xsd11AnyElement(child, self.schema, self)) elif child.tag in (XSD_SEQUENCE, XSD_CHOICE, XSD_ALL): self._group.append(Xsd11Group(child, self.schema, self)) elif child.tag == XSD_GROUP: try: ref = self.schema.resolve_qname(child.attrib['ref']) except (KeyError, ValueError, RuntimeError) as err: if 'ref' not in child.attrib: self.parse_error("missing attribute 'ref' in local group", child) else: self.parse_error(err, child) continue if ref != self.name: xsd_group = Xsd11Group(child, self.schema, self) self._group.append(xsd_group) if (self.model != 'all') ^ (xsd_group.model != 'all'): msg = "an xs:%s group cannot include a reference to an xs:%s group" self.parse_error(msg % (self.model, xsd_group.model)) self.pop() elif self.redefine is None: self.parse_error("Circular definition detected for group %r:" % self.name) else: if child.get('minOccurs', '1') != '1' or child.get('maxOccurs', '1') != '1': self.parse_error("Redefined group reference cannot have " "minOccurs/maxOccurs other than 1:") self._group.append(self.redefine) def admits_restriction(self, model: str) -> bool: if self.model == model or self.model == 'all': return True elif self.model == 'choice': return model == 'sequence' or len(self.ref or self) <= 1 else: return model == 'choice' or len(self.ref or self) <= 1 def is_restriction(self, other: ModelParticleType, check_occurs: bool = True) -> bool: if not self._group: return True elif not isinstance(other, ParticleMixin): raise XMLSchemaValueError("the argument 'base' must be a %r instance" % ParticleMixin) elif not isinstance(other, XsdGroup): return self.is_element_restriction(other) elif not other: return False elif len(other) == other.min_occurs == other.max_occurs == 1: if len(self) > 1: return self.is_restriction(other[0], check_occurs) elif self.ref is None and isinstance(self[0], XsdGroup) \ and self[0].is_pointless(parent=self): return self[0].is_restriction(other[0], check_occurs) if other.model == 'sequence': return self.is_sequence_restriction(other) elif other.model == 'all': return self.is_all_restriction(other) else: # other.model == 'choice': return self.is_choice_restriction(other) def is_sequence_restriction(self, other: XsdGroup) -> bool: if not self.has_occurs_restriction(other): return False check_occurs = other.max_occurs != 0 item_iterator = iter(self.iter_model()) item = next(item_iterator, None) for other_item in other.iter_model(): if item is not None and item.is_restriction(other_item, check_occurs): item = next(item_iterator, None) elif not other_item.is_emptiable(): break else: if item is None: return True # Restriction check failed: try another check without removing pointless groups item_iterator = iter(self) item = next(item_iterator, None) for other_item in other.iter_model(): if item is not None and item.is_restriction(other_item, check_occurs): item = next(item_iterator, None) elif not other_item.is_emptiable(): return False return item is None def is_all_restriction(self, other: XsdGroup) -> bool: if not self.has_occurs_restriction(other): return False restriction_items = [x for x in self.iter_model()] base_items = [x for x in other.iter_model()] # If the base includes more wildcard, calculates and appends a # wildcard union for validating wildcard unions in restriction wildcards: List[XsdAnyElement] = [] for w1 in base_items: if isinstance(w1, XsdAnyElement): for w2 in wildcards: if w1.process_contents == w2.process_contents and w1.occurs == w2.occurs: w2.union(w1) w2.extended = True break else: wildcards.append(w1.copy()) base_items.extend(w for w in wildcards if hasattr(w, 'extended')) if self.model != 'choice': restriction_wildcards = [e for e in restriction_items if isinstance(e, XsdAnyElement)] for other_item in base_items: min_occurs, max_occurs = 0, other_item.max_occurs for k in range(len(restriction_items) - 1, -1, -1): item = restriction_items[k] if item.is_restriction(other_item, check_occurs=False): if max_occurs is None: min_occurs += item.min_occurs elif item.max_occurs is None or max_occurs < item.max_occurs or \ min_occurs + item.min_occurs > max_occurs: continue else: min_occurs += item.min_occurs max_occurs -= item.max_occurs restriction_items.remove(item) if not min_occurs or max_occurs == 0: break else: if self.model == 'all' and restriction_wildcards: if not isinstance(other_item, XsdGroup) and other_item.type \ and other_item.type.name != XSD_ANY_TYPE: for w in restriction_wildcards: if w.is_matching(other_item.name, self.target_namespace): return False if min_occurs < other_item.min_occurs: break else: if not restriction_items: return True return False # Restriction with a choice model: this a more complex case # because the not emptiable elements of the base group have # to be included in each item of the choice group. not_emptiable_items = {x for x in base_items if x.min_occurs} for other_item in base_items: min_occurs, max_occurs = 0, other_item.max_occurs for k in range(len(restriction_items) - 1, -1, -1): item = restriction_items[k] if item.is_restriction(other_item, check_occurs=False): if max_occurs is None: min_occurs += item.min_occurs elif item.max_occurs is None or max_occurs < item.max_occurs or \ min_occurs + item.min_occurs > max_occurs: continue else: min_occurs += item.min_occurs max_occurs -= item.max_occurs if not_emptiable_items: if len(not_emptiable_items) > 1: continue if other_item not in not_emptiable_items: continue restriction_items.remove(item) if not min_occurs or max_occurs == 0: break if min_occurs < other_item.min_occurs: break else: if not restriction_items: return True if any(not isinstance(x, XsdGroup) for x in restriction_items): return False # If the remaining items are groups try to verify if they are all # restrictions of the 'all' group and if each group contains all # not emptiable elements. for group in restriction_items: if not group.is_restriction(other): return False for item in not_emptiable_items: for e in group: if e.name == item.name: break else: return False else: return True def is_choice_restriction(self, other: XsdGroup) -> bool: restriction_items = [x for x in self.iter_model()] has_not_empty_item = any(e.max_occurs != 0 for e in restriction_items) check_occurs = other.max_occurs != 0 max_occurs: Optional[int] = 0 other_max_occurs: Optional[int] = 0 for other_item in other.iter_model(): for item in restriction_items: if other_item is item or item.is_restriction(other_item, check_occurs): if max_occurs is not None: effective_max_occurs = item.effective_max_occurs if effective_max_occurs is None: max_occurs = None elif self.model == 'choice': max_occurs = max(max_occurs, effective_max_occurs) else: max_occurs += effective_max_occurs if other_max_occurs is not None: effective_max_occurs = other_item.effective_max_occurs if effective_max_occurs is None: other_max_occurs = None else: other_max_occurs = max(other_max_occurs, effective_max_occurs) break elif item.max_occurs != 0: continue elif not other_item.is_matching(item.name, self.default_namespace): continue elif has_not_empty_item: break else: return False else: continue restriction_items.remove(item) if restriction_items: return False elif other_max_occurs is None: if other.max_occurs != 0: return True other_max_occurs = 0 elif other.max_occurs is None: if other_max_occurs != 0: return True other_max_occurs = 0 else: other_max_occurs *= other.max_occurs if max_occurs is None: return self.max_occurs == 0 elif self.max_occurs is None: return max_occurs == 0 else: return other_max_occurs >= max_occurs * self.max_occurs �������������������������������������xmlschema-1.10.0/xmlschema/validators/helpers.py����������������������������������������������������0000664�0000000�0000000�00000014074�14211403446�0021724�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from decimal import Decimal from math import isinf, isnan from typing import Optional, Set, Union from xml.etree.ElementTree import Element from elementpath import datatypes from ..exceptions import XMLSchemaValueError from .exceptions import XMLSchemaValidationError XSD_FINAL_ATTRIBUTE_VALUES = {'restriction', 'extension', 'list', 'union'} def get_xsd_derivation_attribute(elem: Element, attribute: str, values: Optional[Set[str]] = None) -> str: """ Get a derivation attribute (maybe 'block', 'blockDefault', 'final' or 'finalDefault') checking the items with the values arguments. Returns a string. :param elem: the Element instance. :param attribute: the attribute name. :param values: a set of admitted values when the attribute value is not '#all'. """ value = elem.get(attribute) if value is None: return '' if values is None: values = XSD_FINAL_ATTRIBUTE_VALUES items = value.split() if len(items) == 1 and items[0] == '#all': return ' '.join(values) elif not all(s in values for s in items): raise ValueError("wrong value %r for attribute %r" % (value, attribute)) return value # # XSD built-in types validator functions def decimal_validator(value: Union[Decimal, int, float, str]) -> None: try: if not isinstance(value, (Decimal, float)): datatypes.DecimalProxy.validate(value) elif isinf(value) or isnan(value): raise ValueError() except (ValueError, TypeError): raise XMLSchemaValidationError(decimal_validator, value, "value is not a valid xs:decimal") from None def qname_validator(value: str) -> None: if datatypes.QName.pattern.match(value) is None: raise XMLSchemaValidationError(qname_validator, value, "value is not an xs:QName") def byte_validator(value: int) -> None: if not (-2**7 <= value < 2 ** 7): raise XMLSchemaValidationError(int_validator, value, "value must be -128 <= x < 128") def short_validator(value: int) -> None: if not (-2**15 <= value < 2 ** 15): raise XMLSchemaValidationError(short_validator, value, "value must be -2^15 <= x < 2^15") def int_validator(value: int) -> None: if not (-2**31 <= value < 2 ** 31): raise XMLSchemaValidationError(int_validator, value, "value must be -2^31 <= x < 2^31") def long_validator(value: int) -> None: if not (-2**63 <= value < 2 ** 63): raise XMLSchemaValidationError(long_validator, value, "value must be -2^63 <= x < 2^63") def unsigned_byte_validator(value: int) -> None: if not (0 <= value < 2 ** 8): raise XMLSchemaValidationError(unsigned_byte_validator, value, "value must be 0 <= x < 256") def unsigned_short_validator(value: int) -> None: if not (0 <= value < 2 ** 16): raise XMLSchemaValidationError(unsigned_short_validator, value, "value must be 0 <= x < 2^16") def unsigned_int_validator(value: int) -> None: if not (0 <= value < 2 ** 32): raise XMLSchemaValidationError(unsigned_int_validator, value, "value must be 0 <= x < 2^32") def unsigned_long_validator(value: int) -> None: if not (0 <= value < 2 ** 64): raise XMLSchemaValidationError(unsigned_long_validator, value, "value must be 0 <= x < 2^64") def negative_int_validator(value: int) -> None: if value >= 0: raise XMLSchemaValidationError(negative_int_validator, value, "value must be negative") def positive_int_validator(value: int) -> None: if value <= 0: raise XMLSchemaValidationError(positive_int_validator, value, "value must be positive") def non_positive_int_validator(value: int) -> None: if value > 0: raise XMLSchemaValidationError(non_positive_int_validator, value, "value must be non positive") def non_negative_int_validator(value: int) -> None: if value < 0: raise XMLSchemaValidationError(non_negative_int_validator, value, "value must be non negative") def hex_binary_validator(value: Union[str, datatypes.HexBinary]) -> None: if not isinstance(value, datatypes.HexBinary) and \ datatypes.HexBinary.pattern.match(value) is None: raise XMLSchemaValidationError(hex_binary_validator, value, "not an hexadecimal number") def base64_binary_validator(value: Union[str, datatypes.Base64Binary]) -> None: if isinstance(value, datatypes.Base64Binary): return value = value.replace(' ', '') if not value: return match = datatypes.Base64Binary.pattern.match(value) if match is None or match.group(0) != value: raise XMLSchemaValidationError(base64_binary_validator, value, "not a base64 encoding") def error_type_validator(value: object) -> None: raise XMLSchemaValidationError(error_type_validator, value, "no value is allowed for xs:error type") # # XSD builtin decoding functions def boolean_to_python(value: str) -> bool: if value in {'true', '1'}: return True elif value in {'false', '0'}: return False else: raise XMLSchemaValueError('{!r} is not a boolean value'.format(value)) def python_to_boolean(value: object) -> str: return str(value).lower() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/identities.py�������������������������������������������������0000664�0000000�0000000�00000045067�14211403446�0022431�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for other XML Schema identity constraints. """ import re import math from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Pattern, \ Tuple, Union, Counter from elementpath import XPath2Parser, ElementPathError, XPathToken, XPathContext, \ translate_pattern, datatypes from ..exceptions import XMLSchemaTypeError, XMLSchemaValueError from ..names import XSD_QNAME, XSD_UNIQUE, XSD_KEY, XSD_KEYREF, XSD_SELECTOR, XSD_FIELD from ..helpers import get_qname, get_extended_qname from ..aliases import ElementType, SchemaType, NamespacesType, AtomicValueType from ..xpath import iter_schema_nodes from .xsdbase import XsdComponent from .attributes import XsdAttribute if TYPE_CHECKING: from .elements import XsdElement IdentityFieldItemType = Union[AtomicValueType, XsdAttribute, Tuple[Any, ...], None] IdentityCounterType = Tuple[IdentityFieldItemType, ...] IdentityMapType = Dict[Union['XsdKey', 'XsdKeyref', str, None], Union['IdentityCounter', 'KeyrefCounter']] XSD_IDENTITY_XPATH_SYMBOLS = frozenset(( 'processing-instruction', 'following-sibling', 'preceding-sibling', 'ancestor-or-self', 'attribute', 'following', 'namespace', 'preceding', 'ancestor', 'position', 'comment', 'parent', 'child', 'false', 'text', 'node', 'true', 'last', 'not', 'and', 'mod', 'div', 'or', '..', '//', '!=', '<=', '>=', '(', ')', '[', ']', '.', '@', ',', '/', '|', '*', '-', '=', '+', '<', '>', ':', '(end)', '(unknown)', '(invalid)', '(name)', '(string)', '(float)', '(decimal)', '(integer)', '::', '{', '}', )) # XSD identities use a restricted parser and a context for iterate element # references. The XMLSchemaProxy is not used for the specific selection of # fields and elements and the XSD fields are got at first validation run. class IdentityXPathContext(XPathContext): _iter_nodes = staticmethod(iter_schema_nodes) class IdentityXPathParser(XPath2Parser): symbol_table = { k: v for k, v in XPath2Parser.symbol_table.items() # type: ignore[misc] if k in XSD_IDENTITY_XPATH_SYMBOLS } SYMBOLS = XSD_IDENTITY_XPATH_SYMBOLS class XsdSelector(XsdComponent): """Class for defining an XPath selector for an XSD identity constraint.""" _ADMITTED_TAGS = {XSD_SELECTOR} xpath_default_namespace = '' pattern: Union[str, Pattern[str]] = translate_pattern( r"(\.//)?(((child::)?((\i\c*:)?(\i\c*|\*)))|\.)(/(((child::)?" r"((\i\c*:)?(\i\c*|\*)))|\.))*(\|(\.//)?(((child::)?((\i\c*:)?" r"(\i\c*|\*)))|\.)(/(((child::)?((\i\c*:)?(\i\c*|\*)))|\.))*)*", back_references=False, lazy_quantifiers=False, anchors=False ) token = None # type: XPathToken parser = None # type: IdentityXPathParser def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional['XsdIdentity']) -> None: super(XsdSelector, self).__init__(elem, schema, parent) def _parse(self) -> None: try: self.path = self.elem.attrib['xpath'] except KeyError: self.parse_error("'xpath' attribute required") self.path = '*' else: path = self.path.replace(' ', '') try: _match = self.pattern.match(path) # type: ignore[union-attr] except AttributeError: # Compile regex pattern self.__class__.pattern = re.compile(self.pattern) _match = self.pattern.match(path) # type: ignore[union-attr] if not _match: msg = "invalid XPath expression for an {}" self.parse_error(msg.format(self.__class__.__name__)) # XSD 1.1 xpathDefaultNamespace attribute if self.schema.XSD_VERSION > '1.0': if 'xpathDefaultNamespace' in self.elem.attrib: self.xpath_default_namespace = self._parse_xpath_default_namespace(self.elem) else: self.xpath_default_namespace = self.schema.xpath_default_namespace self.parser = IdentityXPathParser( namespaces=self.namespaces, strict=False, compatibility_mode=True, default_namespace=self.xpath_default_namespace, ) try: self.token = self.parser.parse(self.path) except ElementPathError as err: self.token = self.parser.parse('*') self.parse_error(err) def __repr__(self) -> str: return '%s(path=%r)' % (self.__class__.__name__, self.path) @property def built(self) -> bool: return self.token is not None @property def target_namespace(self) -> str: # TODO: implement a property in elementpath for getting XPath token's namespace if self.token is None: pass # xpathDefaultNamespace="##targetNamespace" elif self.token.symbol == ':': return self.token[1].namespace or self.xpath_default_namespace elif self.token.symbol == '@' and self.token[0].symbol == ':': return self.token[0][1].namespace or self.xpath_default_namespace return self.schema.target_namespace class XsdFieldSelector(XsdSelector): """Class for defining an XPath field selector for an XSD identity constraint.""" _ADMITTED_TAGS = {XSD_FIELD} pattern = translate_pattern( r"(\.//)?((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)/)*((((child::)?" r"((\i\c*:)?(\i\c*|\*)))|\.)|((attribute::|@)((\i\c*:)?(\i\c*|\*))))" r"(\|(\.//)?((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)/)*" r"((((child::)?((\i\c*:)?(\i\c*|\*)))|\.)|" r"((attribute::|@)((\i\c*:)?(\i\c*|\*)))))*", back_references=False, lazy_quantifiers=False, anchors=False ) class XsdIdentity(XsdComponent): """ Common class for XSD identity constraints. :ivar selector: the XPath selector of the identity constraint. :ivar fields: a list containing the XPath field selectors of the identity constraint. """ name: str local_name: str prefixed_name: str parent: 'XsdElement' ref: Optional['XsdIdentity'] selector = None # type: XsdSelector fields = () # type: Union[Tuple[()], List[XsdFieldSelector]] # XSD elements bound by selector (for speed-up and for lazy mode) elements: Union[Tuple[()], Dict['XsdElement', Optional[IdentityCounterType]]] = () def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional['XsdElement']) -> None: super(XsdIdentity, self).__init__(elem, schema, parent) def _parse(self) -> None: try: self.name = get_qname(self.target_namespace, self.elem.attrib['name']) except KeyError: self.parse_error("missing required attribute 'name'") self.name = '' for child in self.elem: if child.tag == XSD_SELECTOR: self.selector = XsdSelector(child, self.schema, self) break else: self.parse_error("missing 'selector' declaration.") self.fields = [] for child in self.elem: if child.tag == XSD_FIELD: self.fields.append(XsdFieldSelector(child, self.schema, self)) def build(self) -> None: if self.ref is True: # type: ignore[comparison-overlap] try: ref = self.maps.identities[self.name] except KeyError: self.parse_error("unknown identity constraint {!r}".format(self.name)) return else: if not isinstance(ref, self.__class__): self.parse_error("attribute 'ref' points to a different kind constraint") self.selector = ref.selector self.fields = ref.fields self.ref = ref context = IdentityXPathContext(self.schema, item=self.parent) # type: ignore self.elements = {} try: for e in self.selector.token.select_results(context): if not isinstance(e, XsdComponent) or isinstance(e, XsdAttribute): self.parse_error("selector xpath expression can only select elements") elif e.name is not None: if TYPE_CHECKING: assert isinstance(e, XsdElement) # for mypy checks with Python 3.7 self.elements[e] = None except AttributeError: pass else: if not self.elements: # Try to detect target XSD elements extracting QNames # of the leaf elements from the XPath expression and # use them to match global elements. qname: Any for qname in self.selector.token.iter_leaf_elements(): xsd_element = self.maps.elements.get( get_extended_qname(qname, self.namespaces) ) if xsd_element is not None and \ not isinstance(xsd_element, tuple) and \ xsd_element not in self.elements: self.elements[xsd_element] = None @property def built(self) -> bool: return not isinstance(self.elements, tuple) def get_fields(self, elem: Union[ElementType, 'XsdElement'], namespaces: Optional[NamespacesType] = None, decoders: Optional[Tuple[XsdAttribute, ...]] = None) -> IdentityCounterType: """ Get fields for a schema or instance context element. :param elem: an Element or an XsdElement :param namespaces: is an optional mapping from namespace prefix to URI. :param decoders: context schema fields decoders. :return: a tuple with field values. An empty field is replaced by `None`. """ fields: List[IdentityFieldItemType] = [] if not isinstance(elem, XsdComponent): context_class = XPathContext else: context_class = IdentityXPathContext result: Any value: Union[AtomicValueType, None] for k, field in enumerate(self.fields): result = field.token.get_results(context_class(elem)) # type: ignore if not result: if decoders is not None and decoders[k] is not None: value = decoders[k].value_constraint if value is not None: if decoders[k].type.root_type.name == XSD_QNAME: value = get_extended_qname(value, namespaces) if isinstance(value, list): fields.append(tuple(value)) elif isinstance(value, bool): fields.append((value, bool)) elif not isinstance(value, float): fields.append(value) elif math.isnan(value): fields.append(('nan', float)) else: fields.append((value, float)) continue if not isinstance(self, XsdKey) or 'ref' in elem.attrib and \ self.schema.meta_schema is None and self.schema.XSD_VERSION != '1.0': fields.append(None) elif field.target_namespace not in self.maps.namespaces: fields.append(None) else: msg = "missing key field {!r} for {!r}" raise XMLSchemaValueError(msg.format(field.path, self)) elif len(result) == 1: if decoders is None or decoders[k] is None: fields.append(result[0]) else: if decoders[k].type.content_type_label not in ('simple', 'mixed'): raise XMLSchemaTypeError("%r field doesn't have a simple type!" % field) value = decoders[k].data_value(result[0]) if decoders[k].type.root_type.name == XSD_QNAME: if isinstance(value, str): value = get_extended_qname(value, namespaces) elif isinstance(value, datatypes.QName): value = value.expanded_name if isinstance(value, list): fields.append(tuple(value)) elif isinstance(value, bool): fields.append((value, bool)) elif not isinstance(value, float): fields.append(value) elif math.isnan(value): fields.append(('nan', float)) else: fields.append((value, float)) else: raise XMLSchemaValueError("%r field selects multiple values!" % field) return tuple(fields) def get_counter(self, enabled: bool = True) -> 'IdentityCounter': return IdentityCounter(self, enabled) class XsdUnique(XsdIdentity): _ADMITTED_TAGS = {XSD_UNIQUE} class XsdKey(XsdIdentity): _ADMITTED_TAGS = {XSD_KEY} class XsdKeyref(XsdIdentity): """ Implementation of xs:keyref. :ivar refer: reference to a *xs:key* declaration that must be in the same element \ or in a descendant element. """ _ADMITTED_TAGS = {XSD_KEYREF} refer: Optional[Union[str, XsdKey]] = None refer_path = '.' def _parse(self) -> None: super(XsdKeyref, self)._parse() try: self.refer = self.schema.resolve_qname(self.elem.attrib['refer']) except (KeyError, ValueError, RuntimeError) as err: if 'refer' not in self.elem.attrib: self.parse_error("missing required attribute 'refer'") else: self.parse_error(err) def build(self) -> None: super(XsdKeyref, self).build() if isinstance(self.refer, (XsdKey, XsdUnique)): return # referenced key/unique identity constraint already set elif isinstance(self.ref, XsdKeyref): self.refer = self.ref.refer if self.refer is None: return # attribute or key/unique identity constraint missing elif isinstance(self.refer, str): refer = self.parent.identities.get(self.refer) if refer is not None and refer.ref is None: self.refer = refer # type: ignore[assignment] else: try: self.refer = self.maps.identities[self.refer] # type: ignore[assignment] except KeyError: self.parse_error("key/unique identity constraint %r is missing" % self.refer) return if not isinstance(self.refer, (XsdKey, XsdUnique)): self.parse_error("reference to a non key/unique identity constraint %r" % self.refer) elif len(self.refer.fields) != len(self.fields): self.parse_error("field cardinality mismatch between %r and %r" % (self, self.refer)) elif self.parent is not self.refer.parent: refer_path = self.refer.parent.get_path(ancestor=self.parent) if refer_path is None: # From a note in par. 3.11.5 Part 1 of XSD 1.0 spec: "keyref # identity-constraints may be defined on domains distinct from # the embedded domain of the identity-constraint they reference, # or the domains may be the same but self-embedding at some depth. # In either case the node table for the referenced identity-constraint # needs to propagate upwards, with conflict resolution." refer_path = self.parent.get_path(ancestor=self.refer.parent, reverse=True) if refer_path is None: path1 = self.parent.get_path(reverse=True) path2 = self.refer.parent.get_path() assert path1 is not None assert path2 is not None refer_path = f'{path1}/{path2}' self.refer_path = refer_path @property def built(self) -> bool: return not isinstance(self.elements, tuple) and isinstance(self.refer, XsdIdentity) def get_counter(self, enabled: bool = True) -> 'KeyrefCounter': return KeyrefCounter(self, enabled) class Xsd11Unique(XsdUnique): def _parse(self) -> None: if self._parse_reference(): self.ref = True # type: ignore[assignment] else: super(Xsd11Unique, self)._parse() class Xsd11Key(XsdKey): def _parse(self) -> None: if self._parse_reference(): self.ref = True # type: ignore[assignment] else: super(Xsd11Key, self)._parse() class Xsd11Keyref(XsdKeyref): def _parse(self) -> None: if self._parse_reference(): self.ref = True # type: ignore[assignment] else: super(Xsd11Keyref, self)._parse() class IdentityCounter: def __init__(self, identity: XsdIdentity, enabled: bool = True) -> None: self.counter: Counter[IdentityCounterType] = Counter[IdentityCounterType]() self.identity = identity self.enabled = enabled def __repr__(self) -> str: return "%s%r" % (self.__class__.__name__[:-7], self.counter) def clear(self) -> None: self.counter.clear() self.enabled = True def increase(self, fields: IdentityCounterType) -> None: self.counter[fields] += 1 if self.counter[fields] == 2: msg = "duplicated value {!r} for {!r}" raise XMLSchemaValueError(msg.format(fields, self.identity)) class KeyrefCounter(IdentityCounter): identity: XsdKeyref def increase(self, fields: IdentityCounterType) -> None: self.counter[fields] += 1 def iter_errors(self, identities: IdentityMapType) -> Iterator[XMLSchemaValueError]: refer_values = identities[self.identity.refer].counter for v in filter(lambda x: x not in refer_values, self.counter): if len(v) == 1 and v[0] in refer_values: continue elif self.counter[v] > 1: msg = "value {} not found for {!r} ({} times)" yield XMLSchemaValueError(msg.format(v, self.identity.refer, self.counter[v])) else: msg = "value {} not found for {!r}" yield XMLSchemaValueError(msg.format(v, self.identity.refer)) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/models.py�����������������������������������������������������0000664�0000000�0000000�00000046045�14211403446�0021550�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains a function and a class for validating XSD content models. """ from collections import defaultdict, deque from typing import Any, Counter, Dict, Iterable, Iterator, List, Optional, Tuple, Union from ..exceptions import XMLSchemaValueError from ..aliases import ModelGroupType, ModelParticleType, SchemaElementType from . import groups AdvanceYieldedType = Tuple[ModelParticleType, int, List[SchemaElementType]] EncodedContentType = Union[Dict[Union[int, str], List[Any]], List[Tuple[Union[int, str], List[Any]]]] ContentItemType = Tuple[Union[int, str], Any] def distinguishable_paths(path1: List[ModelParticleType], path2: List[ModelParticleType]) -> bool: """ Checks if two model paths are distinguishable in a deterministic way, without looking forward or backtracking. The arguments are lists containing paths from the base group of the model to a couple of leaf elements. Returns `True` if there is a deterministic separation between paths, `False` if the paths are ambiguous. """ e: ModelParticleType for k, e in enumerate(path1): if e not in path2: if not k: return True depth = k - 1 break else: depth = 0 if path1[depth].max_occurs == 0: return True univocal1 = univocal2 = True if path1[depth].model == 'sequence': # type: ignore[union-attr] idx1 = path1[depth].index(path1[depth + 1]) idx2 = path2[depth].index(path2[depth + 1]) before1 = any(not e.is_emptiable() for e in path1[depth][:idx1]) after1 = before2 = any(not e.is_emptiable() for e in path1[depth][idx1 + 1:idx2]) after2 = any(not e.is_emptiable() for e in path1[depth][idx2 + 1:]) else: before1 = after1 = before2 = after2 = False for k in range(depth + 1, len(path1) - 1): univocal1 &= path1[k].is_univocal() idx = path1[k].index(path1[k + 1]) if path1[k].model == 'sequence': # type: ignore[union-attr] before1 |= any(not e.is_emptiable() for e in path1[k][:idx]) after1 |= any(not e.is_emptiable() for e in path1[k][idx + 1:]) elif any(e.is_emptiable() for e in path1[k] if e is not path1[k][idx]): univocal1 = False for k in range(depth + 1, len(path2) - 1): univocal2 &= path2[k].is_univocal() idx = path2[k].index(path2[k + 1]) if path2[k].model == 'sequence': # type: ignore[union-attr] before2 |= any(not e.is_emptiable() for e in path2[k][:idx]) after2 |= any(not e.is_emptiable() for e in path2[k][idx + 1:]) elif any(e.is_emptiable() for e in path2[k] if e is not path2[k][idx]): univocal2 = False if path1[depth].model != 'sequence': # type: ignore[union-attr] if before1 and before2: return True elif before1: return univocal1 and path1[-1].is_univocal() or after1 or path1[depth].max_occurs == 1 elif before2: return univocal2 and path2[-1].is_univocal() or after2 or path2[depth].max_occurs == 1 else: return False elif path1[depth].max_occurs == 1: return before2 or (before1 or univocal1) and (path1[-1].is_univocal() or after1) else: return (before2 or (before1 or univocal1) and (path1[-1].is_univocal() or after1)) and \ (before1 or (before2 or univocal2) and (path2[-1].is_univocal() or after2)) class ModelVisitor: """ A visitor design pattern class that can be used for validating XML data related to an XSD model group. The visit of the model is done using an external match information, counting the occurrences and yielding tuples in case of model's item occurrence errors. Ends setting the current element to `None`. :param root: the root model group. :ivar occurs: the Counter instance for keeping track of occurrences of XSD elements and groups. :ivar element: the current XSD element, initialized to the first element of the model. :ivar group: the current XSD model group, initialized to *root* argument. :ivar items: the current XSD group's items iterator. :ivar match: if the XSD group has an effective item match. """ _groups: List[Tuple[ModelGroupType, Iterator[ModelParticleType], bool]] element: Optional[SchemaElementType] def __init__(self, root: ModelGroupType) -> None: self._groups = [] self.root = root self.occurs = Counter[Union[ModelParticleType, Tuple[ModelParticleType]]]() self.element = None self.group = root self.items = self.iter_group() self.match = False self._start() def __repr__(self) -> str: return '%s(root=%r)' % (self.__class__.__name__, self.root) def clear(self) -> None: del self._groups[:] self.occurs.clear() self.element = None self.group = self.root self.items = self.iter_group() self.match = False def _start(self) -> None: while True: item = next(self.items, None) if item is None: if not self._groups: break self.group, self.items, self.match = self._groups.pop() elif not isinstance(item, groups.XsdGroup): self.element = item break elif item: self._groups.append((self.group, self.items, self.match)) self.group = item self.items = self.iter_group() self.match = False @property def expected(self) -> List[SchemaElementType]: """ Returns the expected elements of the current and descendant groups. """ expected: List[SchemaElementType] = [] items: Union[ModelGroupType, Iterator[ModelParticleType]] if self.group.model == 'choice': items = self.group elif self.group.model == 'all': items = (e for e in self.group if e.min_occurs > self.occurs[e]) else: items = (e for e in self.group if e.min_occurs > self.occurs[e]) for e in items: if isinstance(e, groups.XsdGroup): expected.extend(e.iter_elements()) else: expected.append(e) expected.extend(e.maps.substitution_groups.get(e.name or '', ())) return expected def restart(self) -> None: self.clear() self._start() def stop(self) -> Iterator[AdvanceYieldedType]: while self.element is not None: for e in self.advance(): yield e def iter_group(self) -> Iterator[ModelParticleType]: """Returns an iterator for the current model group.""" if self.group.max_occurs == 0: return iter(()) elif self.group.model != 'all': return iter(self.group) else: return (e for e in self.group.iter_elements() if not e.is_over(self.occurs[e])) def advance(self, match: bool = False) -> Iterator[AdvanceYieldedType]: """ Generator function for advance to the next element. Yields tuples with particles information when occurrence violation is found. :param match: provides current element match. """ def stop_item(item: ModelParticleType) -> bool: """ Stops element or group matching, incrementing current group counter. :return: `True` if the item has violated the minimum occurrences for itself \ or for the current group, `False` otherwise. """ if isinstance(item, groups.XsdGroup): self.group, self.items, self.match = self._groups.pop() if self.group.model == 'choice': item_occurs = occurs[item] if not item_occurs: return False item_max_occurs = occurs[(item,)] or item_occurs if item.max_occurs is None: min_group_occurs = 1 elif item_occurs % item.max_occurs: min_group_occurs = 1 + item_occurs // item.max_occurs else: min_group_occurs = item_occurs // item.max_occurs max_group_occurs = max(1, item_max_occurs // (item.min_occurs or 1)) occurs[self.group] += min_group_occurs occurs[(self.group,)] += max_group_occurs occurs[item] = 0 self.items = self.iter_group() self.match = False return item.is_missing(item_max_occurs) elif self.group.model == 'all': return False elif self.match: pass elif occurs[item]: self.match = True elif item.is_emptiable(): return False elif self._groups: return stop_item(self.group) elif self.group.min_occurs <= max(occurs[self.group], occurs[(self.group,)]): return stop_item(self.group) else: return True if item is self.group[-1]: for k, item2 in enumerate(self.group, start=1): # pragma: no cover item_occurs = occurs[item2] if not item_occurs: continue item_max_occurs = occurs[(item2,)] or item_occurs if item_max_occurs == 1 or any(not x.is_emptiable() for x in self.group[k:]): self.occurs[self.group] += 1 break min_group_occurs = max(1, item_occurs // (item2.max_occurs or item_occurs)) max_group_occurs = max(1, item_max_occurs // (item2.min_occurs or 1)) occurs[self.group] += min_group_occurs occurs[(self.group,)] += max_group_occurs break return item.is_missing(max(occurs[item], occurs[(item,)])) element, occurs = self.element, self.occurs if element is None: raise XMLSchemaValueError("cannot advance, %r is ended!" % self) if match: occurs[element] += 1 self.match = True if self.group.model == 'all': self.items = (e for e in self.group.iter_elements() if not e.is_over(occurs[e])) elif not element.is_over(occurs[element]): return elif self.group.model == 'choice' and element.is_ambiguous(): return obj = None try: element_occurs = occurs[element] if stop_item(element): yield element, element_occurs, [element] while True: while self.group.is_over(max(occurs[self.group], occurs[(self.group,)])): stop_item(self.group) obj = next(self.items, None) if isinstance(obj, groups.XsdGroup): # inner 'sequence' or 'choice' XsdGroup self._groups.append((self.group, self.items, self.match)) self.group = obj self.items = self.iter_group() self.match = False occurs[obj] = occurs[(obj,)] = 0 elif obj is not None: # XsdElement or XsdAnyElement self.element = obj if self.group.model == 'sequence': occurs[obj] = 0 return elif not self.match: if self.group.model == 'all': if all(e.min_occurs <= occurs[e] for e in self.group.iter_elements()): occurs[self.group] = 1 group, expected = self.group, self.expected if stop_item(group) and expected: yield group, occurs[group], expected elif self.group.model != 'all': self.items, self.match = self.iter_group(), False elif any(e.min_occurs > occurs[e] for e in self.group.iter_elements()): if not self.group.min_occurs: yield self.group, occurs[self.group], self.expected self.group, self.items, self.match = self._groups.pop() elif any(not e.is_over(occurs[e]) for e in self.group): self.items = self.iter_group() self.match = False else: occurs[self.group] = 1 except IndexError: # Model visit ended self.element = None if self.group.is_missing(max(occurs[self.group], occurs[(self.group,)])): if self.group.model == 'choice': yield self.group, occurs[self.group], self.expected elif self.group.model == 'sequence': if obj is not None: yield self.group, occurs[self.group], self.expected elif any(e.min_occurs > occurs[e] for e in self.group): yield self.group, occurs[self.group], self.expected elif self.group.max_occurs is not None and self.group.max_occurs < occurs[self.group]: yield self.group, occurs[self.group], self.expected def sort_content(self, content: EncodedContentType, restart: bool = True) \ -> List[ContentItemType]: if restart: self.restart() return [(name, value) for name, value in self.iter_unordered_content(content)] def iter_unordered_content( self, content: EncodedContentType, default_namespace: Optional[str] = None) -> Iterator[ContentItemType]: """ Takes an unordered content stored in a dictionary of lists and yields the content elements sorted with the ordering defined by the model. Character data parts are yielded at start and between child elements. Ordering is inferred from ModelVisitor instance with any elements that don't fit the schema placed at the end of the returned sequence. Checking the yielded content validity is the responsibility of method *iter_encode* of class :class:`XsdGroup`. :param content: a dictionary of element names to list of element contents \ or an iterable composed of couples of name and value. In case of a \ dictionary the values must be lists where each item is the content \ of a single element. :param default_namespace: the default namespace to apply for matching names. """ consumable_content: Dict[str, Any] if isinstance(content, dict): cdata_content = sorted( ((k, v) for k, v in content.items() if isinstance(k, int)), reverse=True ) consumable_content = {k: deque(v) for k, v in content.items() if not isinstance(k, int)} else: cdata_content = sorted(((k, v) for k, v in content if isinstance(k, int)), reverse=True) consumable_content = defaultdict(deque) for k, v in content: if isinstance(k, str): consumable_content[k].append(v) if cdata_content: yield cdata_content.pop() while self.element is not None and consumable_content: # pragma: no cover for name in consumable_content: if self.element.is_matching(name, default_namespace, group=self.group): yield name, consumable_content[name].popleft() if not consumable_content[name]: del consumable_content[name] for _ in self.advance(True): pass if cdata_content: yield cdata_content.pop() break else: # Consume the return of advance otherwise we get stuck in an infinite loop. for _ in self.advance(False): pass # Add the remaining consumable content onto the end of the data. for name, values in consumable_content.items(): for v in values: yield name, v if cdata_content: yield cdata_content.pop() while cdata_content: yield cdata_content.pop() def iter_collapsed_content( self, content: Iterable[Tuple[Union[int, str], Any]], default_namespace: Optional[str] = None) -> Iterator[ContentItemType]: """ Iterates a content stored in a sequence of couples *(name, value)*, yielding items in the same order of the sequence, except for repetitions of the same tag that don't match with the current element of the :class:`ModelVisitor` instance. These items are included in an unsorted buffer and yielded asap when there is a match with the model's element or at the end of the iteration. This iteration mode, in cooperation with the method *iter_encode* of the class XsdGroup, facilitates the encoding of content formatted with a convention that collapses the children with the same tag into a list (eg. BadgerFish). :param content: an iterable containing couples of names and values. :param default_namespace: the default namespace to apply for matching names. """ prev_name = None unordered_content: Dict[str, Any] = defaultdict(deque) for name, value in content: if isinstance(name, int) or self.element is None: yield name, value continue while self.element is not None: if self.element.is_matching(name, default_namespace, group=self.group): yield name, value prev_name = name for _ in self.advance(True): pass break for key in unordered_content: if self.element.is_matching(key, default_namespace, group=self.group): break else: if prev_name == name: unordered_content[name].append(value) break for _ in self.advance(False): pass continue try: yield key, unordered_content[key].popleft() except IndexError: del unordered_content[key] else: for _ in self.advance(True): pass else: yield name, value prev_name = name # Add the remaining consumable content onto the end of the data. for name, values in unordered_content.items(): for v in values: yield name, v �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/notations.py��������������������������������������������������0000664�0000000�0000000�00000003033�14211403446�0022271�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from typing import Optional from ..names import XSD_NOTATION from ..helpers import get_qname from .xsdbase import XsdComponent class XsdNotation(XsdComponent): """ Class for XSD *notation* declarations. .. <notation id = ID name = NCName public = token system = anyURI {any attributes with non-schema namespace}...> Content: (annotation?) </notation> """ _ADMITTED_TAGS = {XSD_NOTATION} @property def built(self) -> bool: return True def _parse(self) -> None: if self.parent is not None: self.parse_error("a notation declaration must be global") try: self.name = get_qname(self.target_namespace, self.elem.attrib['name']) except KeyError: self.parse_error("a notation must have a 'name' attribute") if 'public' not in self.elem.attrib and 'system' not in self.elem.attrib: self.parse_error("a notation must have a 'public' or a 'system' attribute") @property def public(self) -> Optional[str]: return self.elem.get('public') @property def system(self) -> Optional[str]: return self.elem.get('system') �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/particles.py��������������������������������������������������0000664�0000000�0000000�00000014444�14211403446�0022251�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2021 , SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # from typing import Any, Optional, Tuple, Union from ..exceptions import XMLSchemaValueError from ..aliases import ElementType, ModelParticleType class ParticleMixin: """ Mixin for objects related to XSD Particle Schema Components: https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/structures.html#p https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/structures.html#t :ivar min_occurs: the minOccurs property of the XSD particle. Defaults to 1. :ivar max_occurs: the maxOccurs property of the XSD particle. Defaults to 1, \ a `None` value means 'unbounded'. """ name: Any maps: Any min_occurs: int = 1 max_occurs: Optional[int] = 1 def __init__(self, min_occurs: int = 1, max_occurs: Optional[int] = 1) -> None: self.min_occurs = min_occurs self.max_occurs = max_occurs @property def occurs(self) -> Tuple[int, Optional[int]]: return self.min_occurs, self.max_occurs @property def effective_min_occurs(self) -> int: """ A property calculated from minOccurs, that is equal to minOccurs for elements and may vary for content model groups, in dependance of group model and structure. """ return self.min_occurs @property def effective_max_occurs(self) -> Optional[int]: """ A property calculated from maxOccurs, that is equal to maxOccurs for elements and may vary for content model groups, in dependance of group model and structure. Used for checking restrictions of xs:choice model groups in XSD 1.1. """ return self.max_occurs def is_emptiable(self) -> bool: """ Tests if max_occurs == 0. A zero-length model group is considered emptiable. For model groups the test outcome depends also on nested particles. """ return self.min_occurs == 0 def is_empty(self) -> bool: """ Tests if max_occurs == 0. A zero-length model group is considered empty. """ return self.max_occurs == 0 def is_single(self) -> bool: """ Tests if the particle has max_occurs == 1. For elements the test outcome depends also on parent group. For model groups the test outcome depends also on nested model groups. """ return self.max_occurs == 1 def is_multiple(self) -> bool: """Tests the particle can have multiple occurrences.""" return not self.is_empty() and not self.is_single() def is_ambiguous(self) -> bool: """Tests if min_occurs != max_occurs.""" return self.min_occurs != self.max_occurs def is_univocal(self) -> bool: """Tests if min_occurs == max_occurs.""" return self.min_occurs == self.max_occurs def is_missing(self, occurs: int) -> bool: """Tests if provided occurrences are under the minimum.""" return not self.is_emptiable() if occurs == 0 else self.min_occurs > occurs def is_over(self, occurs: int) -> bool: """Tests if provided occurrences are over the maximum.""" return self.max_occurs is not None and self.max_occurs <= occurs def has_occurs_restriction(self, other: Union[ModelParticleType, 'OccursCalculator']) -> bool: if self.min_occurs < other.min_occurs: return False elif self.max_occurs == 0: return True elif other.max_occurs is None: return True elif self.max_occurs is None: return False else: return self.max_occurs <= other.max_occurs def parse_error(self, message: Any) -> None: raise XMLSchemaValueError(message) def _parse_particle(self, elem: ElementType) -> None: if 'minOccurs' in elem.attrib: try: min_occurs = int(elem.attrib['minOccurs']) except (TypeError, ValueError): self.parse_error("minOccurs value is not an integer value") else: if min_occurs < 0: self.parse_error("minOccurs value must be a non negative integer") else: self.min_occurs = min_occurs max_occurs = elem.get('maxOccurs') if max_occurs is None: if self.min_occurs > 1: self.parse_error("minOccurs must be lesser or equal than maxOccurs") elif max_occurs == 'unbounded': self.max_occurs = None else: try: self.max_occurs = int(max_occurs) except ValueError: self.parse_error("maxOccurs value must be a non negative integer or 'unbounded'") else: if self.min_occurs > self.max_occurs: self.parse_error("maxOccurs must be 'unbounded' or greater than minOccurs") self.max_occurs = None class OccursCalculator: """ An helper class for adding and multiplying min/max occurrences of XSD particles. """ min_occurs: int max_occurs: Optional[int] def __init__(self) -> None: self.min_occurs = self.max_occurs = 0 def __repr__(self) -> str: return '%s(%r, %r)' % (self.__class__.__name__, self.min_occurs, self.max_occurs) def __add__(self, other: ParticleMixin) -> 'OccursCalculator': self.min_occurs += other.min_occurs if self.max_occurs is not None: if other.max_occurs is None: self.max_occurs = None else: self.max_occurs += other.max_occurs return self def __mul__(self, other: ParticleMixin) -> 'OccursCalculator': self.min_occurs *= other.min_occurs if self.max_occurs is None: if other.max_occurs == 0: self.max_occurs = 0 elif other.max_occurs is None: if self.max_occurs != 0: self.max_occurs = None else: self.max_occurs *= other.max_occurs return self def reset(self) -> None: self.min_occurs = self.max_occurs = 0 ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/schemas.py����������������������������������������������������0000664�0000000�0000000�00000307067�14211403446�0021714�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains XMLSchema classes creator for xmlschema package. Two schema classes are created at the end of this module, XMLSchema10 for XSD 1.0 and XMLSchema11 for XSD 1.1. The latter class parses also XSD 1.0 schemas, as prescribed by the standard. """ import sys if sys.version_info < (3, 7): from typing import GenericMeta as ABCMeta else: from abc import ABCMeta import os import logging import threading import warnings import re import sys from copy import copy from itertools import chain from typing import cast, Callable, ItemsView, List, Optional, Dict, Any, \ Set, Union, Tuple, Type, Iterator, Counter from elementpath import XPathToken from ..exceptions import XMLSchemaTypeError, XMLSchemaKeyError, XMLSchemaRuntimeError, \ XMLSchemaValueError, XMLSchemaNamespaceError from ..names import VC_MIN_VERSION, VC_MAX_VERSION, VC_TYPE_AVAILABLE, \ VC_TYPE_UNAVAILABLE, VC_FACET_AVAILABLE, VC_FACET_UNAVAILABLE, XSD_NOTATION, \ XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_GROUP, XSD_SIMPLE_TYPE, XSI_TYPE, \ XSD_COMPLEX_TYPE, XSD_ELEMENT, XSD_SEQUENCE, XSD_CHOICE, XSD_ALL, XSD_ANY, \ XSD_ANY_ATTRIBUTE, XSD_ANY_TYPE, XSD_NAMESPACE, XML_NAMESPACE, XSI_NAMESPACE, \ VC_NAMESPACE, SCHEMAS_DIR, LOCATION_HINTS, XSD_ANNOTATION, XSD_INCLUDE, \ XSD_IMPORT, XSD_REDEFINE, XSD_OVERRIDE, XSD_DEFAULT_OPEN_CONTENT, \ XSD_ANY_SIMPLE_TYPE, XSD_UNION, XSD_LIST, XSD_RESTRICTION from ..etree import etree_element, ParseError from ..aliases import ElementType, XMLSourceType, NamespacesType, LocationsType, \ SchemaType, SchemaSourceType, ConverterType, ComponentClassType, DecodeType, \ EncodeType, BaseXsdType, AtomicValueType, ExtraValidatorType, SchemaGlobalType from ..helpers import prune_etree, get_namespace, get_qname from ..namespaces import NamespaceResourcesMap, NamespaceView from ..resources import is_local_url, is_remote_url, url_path_is_file, \ normalize_locations, fetch_resource, normalize_url, XMLResource from ..converters import XMLSchemaConverter from ..xpath import XMLSchemaProtocol, XMLSchemaProxy, ElementPathMixin from .. import dataobjects from .exceptions import XMLSchemaParseError, XMLSchemaValidationError, XMLSchemaEncodeError, \ XMLSchemaNotBuiltError, XMLSchemaIncludeWarning, XMLSchemaImportWarning from .helpers import get_xsd_derivation_attribute from .xsdbase import check_validation_mode, XsdValidator, XsdComponent, XsdAnnotation from .notations import XsdNotation from .identities import XsdIdentity, XsdKey, XsdKeyref, XsdUnique, \ Xsd11Key, Xsd11Unique, Xsd11Keyref, IdentityCounter, KeyrefCounter, IdentityMapType from .facets import XSD_10_FACETS, XSD_11_FACETS from .simple_types import XsdSimpleType, XsdList, XsdUnion, XsdAtomicRestriction, \ Xsd11AtomicRestriction, Xsd11Union from .attributes import XsdAttribute, XsdAttributeGroup, Xsd11Attribute from .complex_types import XsdComplexType, Xsd11ComplexType from .groups import XsdGroup, Xsd11Group from .elements import XsdElement, Xsd11Element from .wildcards import XsdAnyElement, XsdAnyAttribute, Xsd11AnyElement, \ Xsd11AnyAttribute, XsdDefaultOpenContent from .global_maps import XsdGlobals logger = logging.getLogger('xmlschema') XSD_VERSION_PATTERN = re.compile(r'^\d+\.\d+$') DRIVE_PATTERN = re.compile(r'^[a-zA-Z]:$') # Elements for building dummy groups ATTRIBUTE_GROUP_ELEMENT = etree_element(XSD_ATTRIBUTE_GROUP) ANY_ATTRIBUTE_ELEMENT = etree_element( XSD_ANY_ATTRIBUTE, attrib={'namespace': '##any', 'processContents': 'lax'} ) SEQUENCE_ELEMENT = etree_element(XSD_SEQUENCE) ANY_ELEMENT = etree_element( XSD_ANY, attrib={ 'namespace': '##any', 'processContents': 'lax', 'minOccurs': '0', 'maxOccurs': 'unbounded' }) GLOBAL_TAGS = frozenset((XSD_NOTATION, XSD_SIMPLE_TYPE, XSD_COMPLEX_TYPE, XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_GROUP, XSD_ELEMENT)) class XMLSchemaMeta(ABCMeta): XSD_VERSION: str create_meta_schema: Callable[['XMLSchemaMeta', Optional[str]], SchemaType] def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], dict_: Dict[str, Any]) \ -> 'XMLSchemaMeta': assert bases, "a base class is mandatory" base_class = bases[0] # For backward compatibility (will be removed in v2.0) if 'BUILDERS' in dict_: msg = "'BUILDERS' will be removed in v2.0, provide the appropriate " \ "attributes instead (eg. xsd_element_class = Xsd11Element)" warnings.warn(msg, DeprecationWarning, stacklevel=1) for k, v in dict_['BUILDERS'].items(): if k == 'simple_type_factory': dict_['simple_type_factory'] = staticmethod(v) continue attr_name = 'xsd_{}'.format(k) if not hasattr(base_class, attr_name): continue elif getattr(base_class, attr_name) is not v: dict_[attr_name] = v if isinstance(dict_.get('meta_schema'), str): # Build a new meta-schema class and register it into module's globals meta_schema_file: str = dict_.pop('meta_schema') meta_schema_class_name = 'Meta' + name meta_schema: Optional[SchemaType] meta_schema = getattr(base_class, 'meta_schema', None) if meta_schema is None: meta_bases = bases else: # Use base's meta_schema class as base for the new meta-schema meta_bases = (meta_schema.__class__,) if len(bases) > 1: meta_bases += bases[1:] meta_schema_class = super(XMLSchemaMeta, mcs).__new__( mcs, meta_schema_class_name, meta_bases, dict_ ) meta_schema_class.__qualname__ = meta_schema_class_name module = sys.modules[dict_['__module__']] setattr(module, meta_schema_class_name, meta_schema_class) meta_schema = meta_schema_class.create_meta_schema(meta_schema_file) dict_['meta_schema'] = meta_schema # Create the class and check some basic attributes cls = super(XMLSchemaMeta, mcs).__new__(mcs, name, bases, dict_) if cls.XSD_VERSION not in ('1.0', '1.1'): raise XMLSchemaValueError("XSD_VERSION must be '1.0' or '1.1'") return cls class XMLSchemaBase(XsdValidator, ElementPathMixin[Union[SchemaType, XsdElement]], metaclass=XMLSchemaMeta): """ Base class for an XML Schema instance. :param source: an URI that reference to a resource or a file path or a file-like \ object or a string containing the schema or an Element or an ElementTree document \ or an :class:`XMLResource` instance. A multi source initialization is supported \ providing a not empty list of XSD sources. :param namespace: is an optional argument that contains the URI of the namespace \ that has to used in case the schema has no namespace (chameleon schema). For other \ cases, when specified, it must be equal to the *targetNamespace* of the schema. :param validation: the XSD validation mode to use for build the schema, \ that can be 'strict' (default), 'lax' or 'skip'. :param global_maps: is an optional argument containing an :class:`XsdGlobals` \ instance, a mediator object for sharing declaration data between dependents \ schema instances. :param converter: is an optional argument that can be an :class:`XMLSchemaConverter` \ subclass or instance, used for defining the default XML data converter for XML Schema instance. :param locations: schema extra location hints, that can include custom resource locations \ (eg. local XSD file instead of remote resource) or additional namespaces to import after \ processing schema's import statements. Can be a dictionary or a sequence of couples \ (namespace URI, resource URL). Extra locations passed using a tuple container are not \ normalized. :param base_url: is an optional base URL, used for the normalization of relative paths \ when the URL of the schema resource can't be obtained from the source argument. :param allow: defines the security mode for accessing resource locations. Can be \ 'all', 'remote', 'local' or 'sandbox'. Default is 'all' that means all types of \ URLs are allowed. With 'remote' only remote resource URLs are allowed. With 'local' \ only file paths and URLs are allowed. With 'sandbox' only file paths and URLs that \ are under the directory path identified by source or by the *base_url* argument \ are allowed. :param defuse: defines when to defuse XML data using a `SafeXMLParser`. Can be \ 'always', 'remote' or 'never'. For default defuses only remote XML data. :param timeout: the timeout in seconds for fetching resources. Default is `300`. :param build: defines whether build the schema maps. Default is `True`. :param use_meta: if `True` the schema processor uses the validator meta-schema, \ otherwise a new meta-schema is added at the end. In the latter case the meta-schema \ is rebuilt if any base namespace has been overridden by an import. Ignored if the \ argument *global_maps* is provided. :param use_fallback: if `True` the schema processor uses the validator fallback \ location hints to load well-known namespaces (eg. xhtml). :param loglevel: for setting a different logging level for schema initialization \ and building. For default is WARNING (30). For INFO level set it with 20, for \ DEBUG level with 10. The default loglevel is restored after schema building, \ when exiting the initialization method. :cvar XSD_VERSION: store the XSD version (1.0 or 1.1). :cvar BASE_SCHEMAS: a dictionary from namespace to schema resource for meta-schema bases. :cvar fallback_locations: fallback schema location hints for other standard namespaces. :cvar meta_schema: the XSD meta-schema instance. :cvar attribute_form_default: the schema's *attributeFormDefault* attribute. \ Default is 'unqualified'. :cvar element_form_default: the schema's *elementFormDefault* attribute. \ Default is 'unqualified'. :cvar block_default: the schema's *blockDefault* attribute. Default is ''. :cvar final_default: the schema's *finalDefault* attribute. Default is ''. :cvar default_attributes: the XSD 1.1 schema's *defaultAttributes* attribute. \ Default is ``None``. :cvar xpath_tokens: symbol table for schema bound XPath 2.0 parsers. Initially set to \ ``None`` it's redefined at instance level with a dictionary at first use of the XPath \ selector. The parser symbol table is extended with schema types constructors. :ivar target_namespace: is the *targetNamespace* of the schema, the namespace to which \ belong the declarations/definitions of the schema. If it's empty no namespace is associated \ with the schema. In this case the schema declarations can be reused from other namespaces as \ *chameleon* definitions. :ivar validation: validation mode, can be 'strict', 'lax' or 'skip'. :ivar maps: XSD global declarations/definitions maps. This is an instance of \ :class:`XsdGlobal`, that stores the *global_maps* argument or a new object \ when this argument is not provided. :ivar converter: the default converter used for XML data decoding/encoding. :ivar locations: schema location hints. :ivar namespaces: a dictionary that maps from the prefixes used by the schema \ into namespace URI. :ivar imports: a dictionary of namespace imports of the schema, that maps namespace \ URI to imported schema object, or `None` in case of unsuccessful import. :ivar includes: a dictionary of included schemas, that maps a schema location to an \ included schema. It also comprehend schemas included by "xs:redefine" or \ "xs:override" statements. :ivar warnings: warning messages about failure of import and include elements. :ivar notations: `xsd:notation` declarations. :vartype notations: NamespaceView :ivar types: `xsd:simpleType` and `xsd:complexType` global declarations. :vartype types: NamespaceView :ivar attributes: `xsd:attribute` global declarations. :vartype attributes: NamespaceView :ivar attribute_groups: `xsd:attributeGroup` definitions. :vartype attribute_groups: NamespaceView :ivar groups: `xsd:group` global definitions. :vartype groups: NamespaceView :ivar elements: `xsd:element` global declarations. :vartype elements: NamespaceView """ # Instance attributes annotations source: XMLResource namespaces: NamespacesType converter: Union[ConverterType] locations: NamespaceResourcesMap maps: XsdGlobals imports: Dict[str, Optional[SchemaType]] includes: Dict[str, SchemaType] warnings: List[str] notations: NamespaceView[XsdNotation] types: NamespaceView[BaseXsdType] attributes: NamespaceView[XsdAttribute] attribute_groups: NamespaceView[XsdAttributeGroup] groups: NamespaceView[XsdGroup] elements: NamespaceView[XsdElement] substitution_groups: NamespaceView[List[XsdElement]] identities: NamespaceView[XsdIdentity] XSD_VERSION: str = '1.0' meta_schema: Optional['XMLSchemaBase'] = None BASE_SCHEMAS: Dict[str, str] = {} fallback_locations: Dict[str, str] = LOCATION_HINTS.copy() _locations: Tuple[Tuple[str, str], ...] = () _annotations = None # XSD components classes xsd_notation_class = XsdNotation xsd_complex_type_class = XsdComplexType xsd_attribute_class = XsdAttribute xsd_any_attribute_class = XsdAnyAttribute xsd_attribute_group_class = XsdAttributeGroup xsd_group_class = XsdGroup xsd_element_class = XsdElement xsd_any_class = XsdAnyElement xsd_atomic_restriction_class = XsdAtomicRestriction xsd_list_class = XsdList xsd_union_class = XsdUnion xsd_key_class = XsdKey xsd_keyref_class = XsdKeyref xsd_unique_class = XsdUnique # Schema defaults target_namespace = '' attribute_form_default = 'unqualified' element_form_default = 'unqualified' block_default = '' final_default = '' redefine = None # Additional defaults for XSD 1.1 default_attributes: Optional[Union[str, XsdAttributeGroup]] = None default_open_content = None override = None # Store XPath constructors tokens (for schema and its assertions) xpath_tokens: Optional[Dict[str, Type[XPathToken]]] = None def __init__(self, source: Union[SchemaSourceType, List[SchemaSourceType]], namespace: Optional[str] = None, validation: str = 'strict', global_maps: Optional[XsdGlobals] = None, converter: Optional[ConverterType] = None, locations: Optional[LocationsType] = None, base_url: Optional[str] = None, allow: str = 'all', defuse: str = 'remote', timeout: int = 300, build: bool = True, use_meta: bool = True, use_fallback: bool = True, loglevel: Optional[Union[str, int]] = None) -> None: super(XMLSchemaBase, self).__init__(validation) self.lock = threading.Lock() # Lock for build operations if loglevel is not None: if isinstance(loglevel, str): level = loglevel.strip().upper() if level not in {'DEBUG', 'INFO', 'WARN', 'WARNING', 'ERROR', 'CRITICAL'}: raise XMLSchemaValueError("{!r} is not a valid loglevel".format(loglevel)) logger.setLevel(getattr(logging, level)) else: logger.setLevel(loglevel) elif build and global_maps is None: logger.setLevel(logging.WARNING) if allow == 'sandbox' and base_url is None and is_local_url(source): # Allow sandbox mode without a base_url using the initial schema URL as base assert isinstance(source, str) base_url = os.path.dirname(normalize_url(source)) other_sources: List[SchemaSourceType] if isinstance(source, list): if not source: raise XMLSchemaValueError("no XSD source provided!") other_sources = source[1:] source = source[0] else: other_sources = [] if isinstance(source, XMLResource): self.source = source else: self.source = XMLResource(source, base_url, allow, defuse, timeout) logger.debug("Read schema from %r", self.source.url or self.source.source) self.imports = {} self.includes = {} self.warnings = [] self._root_elements = None # type: Optional[Set[str]] self.name = self.source.name root = self.source.root # Initialize schema's namespaces, the XML namespace is implicitly declared. self.namespaces = self.source.get_namespaces({'xml': XML_NAMESPACE}, root_only=True) if 'targetNamespace' in root.attrib: self.target_namespace = root.attrib['targetNamespace'].strip() if not self.target_namespace: # https://www.w3.org/TR/2004/REC-xmlschema-1-20041028/structures.html#element-schema self.parse_error("the attribute 'targetNamespace' cannot be an empty string", root) elif namespace is not None and self.target_namespace != namespace: msg = "wrong namespace (%r instead of %r) for XSD resource %s" self.parse_error(msg % (self.target_namespace, namespace, self.url), root) if not self.target_namespace and namespace is not None: # Chameleon schema case self.target_namespace = namespace if '' not in self.namespaces: self.namespaces[''] = namespace elif '' not in self.namespaces: # If not declared map the default namespace to no namespace self.namespaces[''] = '' logger.debug("Schema targetNamespace is %r", self.target_namespace) logger.debug("Declared namespaces: %r", self.namespaces) # Parses the schema defaults if 'attributeFormDefault' in root.attrib: self.attribute_form_default = root.attrib['attributeFormDefault'] if 'elementFormDefault' in root.attrib: self.element_form_default = root.attrib['elementFormDefault'] if 'blockDefault' in root.attrib: if self.meta_schema is None: pass # Skip for XSD 1.0 meta-schema that has blockDefault="#all" else: try: self.block_default = get_xsd_derivation_attribute( root, 'blockDefault', {'extension', 'restriction', 'substitution'} ) except ValueError as err: self.parse_error(err, root) if 'finalDefault' in root.attrib: try: self.final_default = get_xsd_derivation_attribute(root, 'finalDefault') except ValueError as err: self.parse_error(err, root) if converter is None: self.converter = XMLSchemaConverter else: self.converter = self.get_converter(converter) if self.meta_schema is None: self.locations = NamespaceResourcesMap() # Meta-schema maps creation (MetaXMLSchema10/11 classes) self.maps = global_maps or XsdGlobals(self) for child in self.source.root: if child.tag == XSD_OVERRIDE: self.include_schema(child.attrib['schemaLocation'], self.base_url) return # Meta-schemas don't need to be checked and don't process imports # Completes the namespaces map with internal declarations, remapping same prefixes. self.namespaces = self.source.get_namespaces(self.namespaces) if locations: if isinstance(locations, tuple): self._locations = locations else: self._locations = tuple(normalize_locations(locations, self.base_url)) self.locations = NamespaceResourcesMap(self.source.get_locations(self._locations)) if not use_fallback: self.fallback_locations = {} with self.meta_schema.lock: if not self.meta_schema.maps.types: self.meta_schema.maps.build() # Create or set the XSD global maps instance if isinstance(global_maps, XsdGlobals): self.maps = global_maps elif global_maps is not None: raise XMLSchemaTypeError("'global_maps' argument must be an %r instance" % XsdGlobals) elif use_meta and self.target_namespace not in self.meta_schema.maps.namespaces: self.maps = self.meta_schema.maps.copy(self, validation) else: self.maps = XsdGlobals(self, validation) if any(ns == VC_NAMESPACE for ns in self.namespaces.values()): # For XSD 1.1+ apply versioning filter to schema tree. See the paragraph # 4.2.2 of XSD 1.1 (Part 1: Structures) definition for details. # Ref: https://www.w3.org/TR/xmlschema11-1/#cip if prune_etree(root, selector=lambda x: not self.version_check(x)): for k in list(root.attrib): if k not in {'targetNamespace', VC_MIN_VERSION, VC_MAX_VERSION}: del root.attrib[k] # Validate the schema document (transforming validation errors to parse errors) if validation != 'skip': for e in self.meta_schema.iter_errors(root, namespaces=self.namespaces): self.parse_error(e.reason or e, elem=e.elem) self._parse_inclusions() self._parse_imports() # Imports by argument (usually from xsi:schemaLocation attribute). for ns in self.locations: if ns not in self.maps.namespaces: self._import_namespace(ns, self.locations[ns]) # XSD 1.1 default declarations (defaultAttributes, defaultOpenContent, # xpathDefaultNamespace) if self.XSD_VERSION > '1.0': self.xpath_default_namespace = self._parse_xpath_default_namespace(root) if 'defaultAttributes' in root.attrib: try: self.default_attributes = self.resolve_qname(root.attrib['defaultAttributes']) except (ValueError, KeyError, RuntimeError) as err: self.parse_error(err, root) for child in root: if child.tag == XSD_DEFAULT_OPEN_CONTENT: self.default_open_content = XsdDefaultOpenContent(child, self) break _source: Union[SchemaSourceType, XMLResource] for _source in other_sources: if not isinstance(_source, XMLResource): _source = XMLResource(_source, base_url, allow, defuse, timeout) if not _source.root.get('targetNamespace') and self.target_namespace: # Adding a chameleon schema: set the namespace with targetNamespace self.add_schema(_source, namespace=self.target_namespace) else: self.add_schema(_source) try: if build: self.maps.build() finally: if loglevel is not None: logger.setLevel(logging.WARNING) # Restore default logging def __getstate__(self) -> Dict[str, Any]: state = self.__dict__.copy() state.pop('lock', None) state.pop('xpath_tokens', None) return state def __setstate__(self, state: Dict[str, Any]) -> None: self.__dict__.update(state) self.lock = threading.Lock() def __repr__(self) -> str: if self.url: return '%s(name=%r, namespace=%r)' % ( self.__class__.__name__, self.name, self.target_namespace ) return '%s(namespace=%r)' % (self.__class__.__name__, self.target_namespace) def __setattr__(self, name: str, value: Any) -> None: if name == 'maps': if self.meta_schema is None and hasattr(self, 'maps'): msg = "cannot change the global maps instance of a meta-schema" raise XMLSchemaValueError(msg) super(XMLSchemaBase, self).__setattr__(name, value) self.notations = NamespaceView(value.notations, self.target_namespace) self.types = NamespaceView(value.types, self.target_namespace) self.attributes = NamespaceView(value.attributes, self.target_namespace) self.attribute_groups = NamespaceView(value.attribute_groups, self.target_namespace) self.groups = NamespaceView(value.groups, self.target_namespace) self.elements = NamespaceView(value.elements, self.target_namespace) self.substitution_groups = NamespaceView(value.substitution_groups, self.target_namespace) self.identities = NamespaceView(value.identities, self.target_namespace) value.register(self) else: if name == 'validation': check_validation_mode(value) super(XMLSchemaBase, self).__setattr__(name, value) def __iter__(self) -> Iterator[XsdElement]: yield from sorted(self.elements.values(), key=lambda x: x.name) def __reversed__(self) -> Iterator[XsdElement]: yield from sorted(self.elements.values(), key=lambda x: x.name, reverse=True) def __len__(self) -> int: return len(self.elements) @property def xpath_proxy(self) -> XMLSchemaProxy: return XMLSchemaProxy(cast(XMLSchemaProtocol, self)) @property def xsd_version(self) -> str: """Compatibility property that returns the class attribute XSD_VERSION.""" return self.XSD_VERSION # XML resource attributes access @property def root(self) -> ElementType: """Root element of the schema.""" return self.source.root def get_text(self) -> str: """Returns the source text of the XSD schema.""" return self.source.get_text() @property def url(self) -> Optional[str]: """Schema resource URL, is `None` if the schema is built from an Element or a string.""" return self.source.url @property def base_url(self) -> Optional[str]: """The base URL of the source of the schema.""" return self.source.base_url @property def filepath(self) -> Optional[str]: """The filepath if the schema is loaded from a local XSD file, `None` otherwise.""" return self.source.filepath @property def allow(self) -> str: """Defines the resource access security mode, can be 'all', 'local' or 'sandbox'.""" return self.source.allow @property def defuse(self) -> str: """Defines when to defuse XML data, can be 'always', 'remote' or 'never'.""" return self.source.defuse @property def timeout(self) -> int: """Timeout in seconds for fetching resources.""" return self.source.timeout @property def use_meta(self) -> bool: """Returns `True` if the class meta-schema is used.""" return self.meta_schema is self.__class__.meta_schema # Schema root attributes @property def tag(self) -> str: """Schema root tag. For compatibility with the ElementTree API.""" return self.source.root.tag @property def id(self) -> Optional[str]: """The schema's *id* attribute, defaults to ``None``.""" return self.source.root.get('id') @property def version(self) -> Optional[str]: """The schema's *version* attribute, defaults to ``None``.""" return self.source.root.get('version') @property def schema_location(self) -> List[Tuple[str, str]]: """ A list of location hints extracted from the *xsi:schemaLocation* attribute of the schema. """ return [(k, v) for k, v in self.source.iter_location_hints() if k] @property def no_namespace_schema_location(self) -> Optional[str]: """ A location hint extracted from the *xsi:noNamespaceSchemaLocation* attribute of the schema. """ for k, v in self.source.iter_location_hints(): if not k: return v return None @property def default_namespace(self) -> Optional[str]: """The namespace associated to the empty prefix ''.""" return self.namespaces.get('') @property def target_prefix(self) -> str: """The prefix associated to the *targetNamespace*.""" for prefix, namespace in self.namespaces.items(): if namespace == self.target_namespace: return prefix return '' @classmethod def builtin_types(cls) -> NamespaceView[BaseXsdType]: """Returns the XSD built-in types of the meta-schema.""" if cls.meta_schema is None: raise XMLSchemaRuntimeError("meta-schema unavailable for %r" % cls) try: meta_schema: SchemaType = cls.meta_schema.maps.namespaces[XSD_NAMESPACE][0] builtin_types = meta_schema.types except KeyError: raise XMLSchemaNotBuiltError(cls.meta_schema, "missing XSD namespace in meta-schema") else: if not builtin_types: cls.meta_schema.build() return builtin_types @property def annotations(self) -> List[XsdAnnotation]: if self._annotations is None: self._annotations = [ XsdAnnotation(child, self) for child in self.source.root if child.tag == XSD_ANNOTATION ] return self._annotations @property def root_elements(self) -> List[XsdElement]: """ The list of global elements that are not used by reference in any model of the schema. This is implemented as lazy property because it's computationally expensive to build when the schema model is complex. """ if not self.elements: return [] elif len(self.elements) == 1: return list(self.elements.values()) elif self._root_elements is None: names = set(e.name for e in self.elements.values()) for xsd_element in self.elements.values(): for e in xsd_element.iter(): if e is xsd_element or isinstance(e, XsdAnyElement): continue elif e.ref or e.parent is None: if e.name in names: names.discard(e.name) if not names: break self._root_elements = set(names) assert self._root_elements is not None return [e for e in self.elements.values() if e.name in self._root_elements] @property def simple_types(self) -> List[XsdSimpleType]: """Returns a list containing the global simple types.""" return [x for x in self.types.values() if isinstance(x, XsdSimpleType)] @property def complex_types(self) -> List[XsdComplexType]: """Returns a list containing the global complex types.""" return [x for x in self.types.values() if isinstance(x, XsdComplexType)] @classmethod def create_meta_schema(cls, source: Optional[str] = None, base_schemas: Union[None, Dict[str, str], List[Tuple[str, str]]] = None, global_maps: Optional[XsdGlobals] = None) -> SchemaType: """ Creates a new meta-schema instance. :param source: an optional argument referencing to or containing the XSD meta-schema \ resource. Required if the schema class doesn't already have a meta-schema. :param base_schemas: an optional dictionary that contains namespace URIs and \ schema locations. If provided is used as substitute for class BASE_SCHEMAS. \ Also a sequence of (namespace, location) items can be provided if there are more \ schema documents for one or more namespaces. :param global_maps: is an optional argument containing an :class:`XsdGlobals` \ instance for the new meta schema. If not provided a new map is created. """ if source is None: if cls.meta_schema is None or cls.meta_schema.url: raise XMLSchemaValueError("Missing meta-schema source URL") source = cast(str, cls.meta_schema.url) _base_schemas: Union[ItemsView[str, str], List[Tuple[str, str]]] if base_schemas is None: _base_schemas = cls.BASE_SCHEMAS.items() elif isinstance(base_schemas, dict): _base_schemas = base_schemas.items() else: try: _base_schemas = [(n, l) for n, l in base_schemas] except ValueError: raise ValueError( "The argument 'base_schemas' is not a dictionary nor a sequence of items" ) meta_schema: SchemaType meta_schema_class = cls if cls.meta_schema is None else cls.meta_schema.__class__ meta_schema = meta_schema_class(source, XSD_NAMESPACE, global_maps=global_maps, defuse='never', build=False) for ns, location in _base_schemas: if ns == XSD_NAMESPACE: meta_schema.include_schema(location=location) else: meta_schema.import_schema(namespace=ns, location=location) return meta_schema def simple_type_factory(self, elem: ElementType, schema: Optional[SchemaType] = None, parent: Optional[XsdComponent] = None) -> XsdSimpleType: """ Factory function for XSD simple types. Parses the xs:simpleType element and its child component, that can be a restriction, a list or an union. Annotations are linked to simple type instance, omitting the inner annotation if both are given. """ if schema is None: schema = self annotation = None try: child = elem[0] except IndexError: return cast(XsdSimpleType, self.maps.types[XSD_ANY_SIMPLE_TYPE]) else: if child.tag == XSD_ANNOTATION: annotation = XsdAnnotation(child, schema, parent) try: child = elem[1] except IndexError: schema.parse_error("(restriction | list | union) expected", elem) return cast(XsdSimpleType, self.maps.types[XSD_ANY_SIMPLE_TYPE]) xsd_type: XsdSimpleType if child.tag == XSD_RESTRICTION: xsd_type = self.xsd_atomic_restriction_class(child, schema, parent) elif child.tag == XSD_LIST: xsd_type = self.xsd_list_class(child, schema, parent) elif child.tag == XSD_UNION: xsd_type = self.xsd_union_class(child, schema, parent) else: schema.parse_error("(restriction | list | union) expected", elem) return cast(XsdSimpleType, self.maps.types[XSD_ANY_SIMPLE_TYPE]) if annotation is not None: xsd_type._annotation = annotation try: xsd_type.name = get_qname(schema.target_namespace, elem.attrib['name']) except KeyError: if parent is None: schema.parse_error("missing attribute 'name' in a global simpleType", elem) xsd_type.name = 'nameless_%s' % str(id(xsd_type)) else: if parent is not None: schema.parse_error("attribute 'name' not allowed for a local simpleType", elem) xsd_type.name = None if 'final' in elem.attrib: try: xsd_type._final = get_xsd_derivation_attribute(elem, 'final') except ValueError as err: xsd_type.parse_error(err, elem) return xsd_type def create_any_content_group(self, parent: Union[XsdComplexType, XsdGroup], any_element: Optional[XsdAnyElement] = None) -> XsdGroup: """ Creates a model group related to schema instance that accepts any content. :param parent: the parent component to set for the any content group. :param any_element: an optional any element to use for the content group. \ When provided it's copied, linked to the group and the minOccurs/maxOccurs \ are set to 0 and 'unbounded'. """ group: XsdGroup = self.xsd_group_class(SEQUENCE_ELEMENT, self, parent) if isinstance(any_element, XsdAnyElement): particle = any_element.copy() particle.min_occurs = 0 particle.max_occurs = None particle.parent = group group.append(particle) else: group.append(self.xsd_any_class(ANY_ELEMENT, self, group)) return group def create_empty_content_group(self, parent: Union[XsdComplexType, XsdGroup], model: str = 'sequence', **attrib: Any) -> XsdGroup: if model == 'sequence': group_elem = etree_element(XSD_SEQUENCE, **attrib) elif model == 'choice': group_elem = etree_element(XSD_CHOICE, **attrib) elif model == 'all': group_elem = etree_element(XSD_ALL, **attrib) else: raise XMLSchemaValueError("'model' argument must be (sequence | choice | all)") group_elem.text = '\n ' return self.xsd_group_class(group_elem, self, parent) def create_any_attribute_group(self, parent: Union[XsdComplexType, XsdElement]) \ -> XsdAttributeGroup: """ Creates an attribute group related to schema instance that accepts any attribute. :param parent: the parent component to set for the any attribute group. """ attribute_group = self.xsd_attribute_group_class( ATTRIBUTE_GROUP_ELEMENT, self, parent ) attribute_group[None] = self.xsd_any_attribute_class( ANY_ATTRIBUTE_ELEMENT, self, attribute_group ) return attribute_group def create_empty_attribute_group(self, parent: Union[XsdComplexType, XsdElement]) \ -> XsdAttributeGroup: """ Creates an empty attribute group related to schema instance. :param parent: the parent component to set for the any attribute group. """ return self.xsd_attribute_group_class(ATTRIBUTE_GROUP_ELEMENT, self, parent) def create_any_type(self) -> XsdComplexType: """ Creates an xs:anyType equivalent type related with the wildcards connected to global maps of the schema instance in order to do a correct namespace lookup during wildcards validation. """ schema = self.meta_schema or self any_type = self.xsd_complex_type_class( elem=etree_element(XSD_COMPLEX_TYPE, name=XSD_ANY_TYPE), schema=schema, parent=None, mixed=True, block='', final='' ) assert isinstance(any_type.content, XsdGroup) any_type.content.append(self.xsd_any_class( ANY_ELEMENT, schema, any_type.content )) any_type.attributes[None] = self.xsd_any_attribute_class( ANY_ATTRIBUTE_ELEMENT, schema, any_type.attributes ) any_type.maps = any_type.content.maps = any_type.content[0].maps = \ any_type.attributes[None].maps = self.maps return any_type def create_element(self, name: str, parent: Optional[XsdComponent] = None, text: Optional[str] = None, **attrib: Any) -> XsdElement: """ Creates an xs:element instance related to schema component. Used as dummy element for validation/decoding/encoding operations of wildcards and complex types. """ elem = etree_element(XSD_ELEMENT, name=name, **attrib) if text is not None: elem.text = text return self.xsd_element_class(elem=elem, schema=self, parent=parent) def copy(self) -> SchemaType: """ Makes a copy of the schema instance. The new instance has independent maps of shared XSD components. """ schema: SchemaType = object.__new__(self.__class__) schema.__dict__.update(self.__dict__) schema.source = copy(self.source) schema.errors = self.errors[:] schema.warnings = self.warnings[:] schema.namespaces = dict(self.namespaces) schema.locations = NamespaceResourcesMap(self.locations) schema.imports = self.imports.copy() schema.includes = self.includes.copy() schema.maps = self.maps.copy(validator=schema) return schema __copy__ = copy @classmethod def check_schema(cls, schema: SchemaType, namespaces: Optional[NamespacesType] = None) -> None: """ Validates the given schema against the XSD meta-schema (:attr:`meta_schema`). :param schema: the schema instance that has to be validated. :param namespaces: is an optional mapping from namespace prefix to URI. :raises: :exc:`XMLSchemaValidationError` if the schema is invalid. """ if cls.meta_schema is None: raise XMLSchemaRuntimeError("meta-schema unavailable for %r" % cls) elif not cls.meta_schema.maps.types: cls.meta_schema.maps.build() for error in cls.meta_schema.iter_errors(schema.source, namespaces=namespaces): raise error def check_validator(self, validation: str = 'strict') -> None: """Checks the status of a schema validator against a validation mode.""" check_validation_mode(validation) if self.built: pass elif self.meta_schema is None: self.build() # Meta-schema lazy build elif validation == 'skip' and self.validation == 'skip' and \ any(isinstance(comp, tuple) or comp.validation_attempted == 'partial' for comp in self.iter_globals()): pass else: raise XMLSchemaNotBuiltError(self, "schema %r is not built" % self) def build(self) -> None: """Builds the schema's XSD global maps.""" self.maps.build() def clear(self) -> None: """Clears the schema's XSD global maps.""" self.maps.clear() @property def built(self) -> bool: if any(not isinstance(g, XsdComponent) or not g.built for g in self.iter_globals()): return False for _ in self.iter_globals(): return True if self.meta_schema is None: return False # No XSD globals: check with a lookup of schema child elements. prefix = '{%s}' % self.target_namespace if self.target_namespace else '' for child in self.source.root: if child.tag in {XSD_REDEFINE, XSD_OVERRIDE}: for e in filter(lambda x: x.tag in GLOBAL_TAGS, child): name = e.get('name') if name is not None: try: if not self.maps.lookup(e.tag, prefix + name if prefix else name).built: return False except KeyError: return False elif child.tag in GLOBAL_TAGS: name = child.get('name') if name is not None: try: if not self.maps.lookup(child.tag, prefix + name if prefix else name).built: return False except KeyError: return False return True @property def validation_attempted(self) -> str: if self.built: return 'full' elif any(isinstance(comp, tuple) or comp.validation_attempted == 'partial' for comp in self.iter_globals()): return 'partial' else: return 'none' def iter_globals(self, schema: Optional[SchemaType] = None) \ -> Iterator[Union[SchemaGlobalType, Tuple[Any, ...]]]: """ Creates an iterator for XSD global definitions/declarations related to schema namespace. :param schema: Optional argument for filtering only globals related to a schema instance. """ if schema is None: yield from self.notations.values() yield from self.types.values() yield from self.attributes.values() yield from self.attribute_groups.values() yield from self.groups.values() yield from self.elements.values() else: def schema_filter(x: Union[XsdComponent, Tuple[ElementType, SchemaType]]) -> bool: if isinstance(x, tuple): return x[1] is schema return x.schema is schema yield from filter(schema_filter, self.notations.values()) yield from filter(schema_filter, self.types.values()) yield from filter(schema_filter, self.attributes.values()) yield from filter(schema_filter, self.attribute_groups.values()) yield from filter(schema_filter, self.groups.values()) yield from filter(schema_filter, self.elements.values()) def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[Union[XsdComponent, SchemaType]]: """ Iterates yielding the schema and its components. For default includes all the relevant components of the schema, excluding only facets and empty attribute groups. The first returned component is the schema itself. :param xsd_classes: provide a class or a tuple of classes to \ restrict the range of component types yielded. """ if xsd_classes is None or isinstance(self, xsd_classes): yield self for xsd_global in self.iter_globals(self): if not isinstance(xsd_global, tuple): yield from xsd_global.iter_components(xsd_classes) def get_schema(self, namespace: str) -> SchemaType: """ Returns the first schema loaded for a namespace. Raises a `KeyError` if the requested namespace is not loaded. """ try: return cast(SchemaType, self.maps.namespaces[namespace][0]) except KeyError: if not namespace: return self raise XMLSchemaKeyError('the namespace {!r} is not loaded'.format(namespace)) from None def get_converter(self, converter: Optional[ConverterType] = None, **kwargs: Any) -> XMLSchemaConverter: """ Returns a new converter instance. :param converter: can be a converter class or instance. If it's an instance \ the new instance is copied from it and configured with the provided arguments. :param kwargs: optional arguments for initialize the converter instance. :return: a converter instance. """ if converter is None: converter = self.converter if isinstance(converter, XMLSchemaConverter): return converter.copy(**kwargs) elif issubclass(converter, XMLSchemaConverter): # noinspection PyCallingNonCallable return converter(**kwargs) else: msg = "'converter' argument must be a %r subclass or instance: %r" raise XMLSchemaTypeError(msg % (XMLSchemaConverter, converter)) def get_locations(self, namespace: str) -> List[str]: """Get a list of location hints for a namespace.""" try: return list(self.locations[namespace]) except KeyError: return [] def get_element(self, tag: str, path: Optional[str] = None, namespaces: Optional[NamespacesType] = None) -> Optional[XsdElement]: if not path: xsd_element = self.find(tag) return xsd_element if isinstance(xsd_element, XsdElement) else None elif path[-1] == '*': xsd_element = self.find(path[:-1] + tag, namespaces) if isinstance(xsd_element, XsdElement): return xsd_element obj = self.maps.elements.get(tag) return obj if isinstance(obj, XsdElement) else None else: xsd_element = self.find(path, namespaces) return xsd_element if isinstance(xsd_element, XsdElement) else None def create_bindings(self, *bases: type, **attrs: Any) -> None: """ Creates data object bindings for XSD elements of the schema. :param bases: base classes to use for creating the binding classes. :param attrs: attribute and method definitions for the binding classes body. """ for xsd_component in self.iter_components(): if isinstance(xsd_component, XsdElement): xsd_component.get_binding(*bases, replace_existing=True, **attrs) def _parse_inclusions(self) -> None: """Processes schema document inclusions and redefinitions/overrides.""" for child in self.source.root: if child.tag == XSD_INCLUDE: try: location = child.attrib['schemaLocation'].strip() logger.info("Include schema from %r", location) self.include_schema(location, self.base_url) except KeyError: # Attribute missing error already found by validation against meta-schema pass except (OSError, IOError) as err: # It is not an error if the location fail to resolve: # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#compound-schema # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#src-include self.warnings.append("Include schema failed: %s." % str(err)) warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) except (XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: msg = 'cannot include schema %r: %s' % (child.attrib['schemaLocation'], err) if isinstance(err, (XMLSchemaParseError, ParseError)): self.parse_error(msg) else: raise type(err)(msg) elif child.tag == XSD_REDEFINE: try: location = child.attrib['schemaLocation'].strip() logger.info("Redefine schema %r", location) schema = self.include_schema(location, self.base_url) except KeyError: # Attribute missing error already found by validation against meta-schema pass except (OSError, IOError) as err: # If the redefine doesn't contain components (annotation excluded) # the statement is equivalent to an include, so no error is generated. # Otherwise fails. self.warnings.append("Redefine schema failed: %s." % str(err)) warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) if any(e.tag != XSD_ANNOTATION and not callable(e.tag) for e in child): self.parse_error(err, child) except (XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: msg = 'cannot redefine schema %r: %s' % (child.attrib['schemaLocation'], err) if isinstance(err, (XMLSchemaParseError, ParseError)): self.parse_error(msg, child) else: raise type(err)(msg) else: schema.redefine = self elif child.tag == XSD_OVERRIDE and self.XSD_VERSION != '1.0': try: location = child.attrib['schemaLocation'].strip() logger.info("Override schema %r", location) schema = self.include_schema(location, self.base_url) except KeyError: # Attribute missing error already found by validation against meta-schema pass except (OSError, IOError) as err: # If the override doesn't contain components (annotation excluded) # the statement is equivalent to an include, so no error is generated. # Otherwise fails. self.warnings.append("Override schema failed: %s." % str(err)) warnings.warn(self.warnings[-1], XMLSchemaIncludeWarning, stacklevel=3) if any(e.tag != XSD_ANNOTATION and not callable(e.tag) for e in child): self.parse_error(str(err), child) else: schema.override = self def include_schema(self, location: str, base_url: Optional[str] = None, build: bool = False) -> SchemaType: """ Includes a schema for the same namespace, from a specific URL. :param location: is the URL of the schema. :param base_url: is an optional base URL for fetching the schema resource. :param build: defines when to build the imported schema, the default is to not build. :return: the included :class:`XMLSchema` instance. """ schema: SchemaType schema_url = fetch_resource(location, base_url) for schema in self.maps.namespaces[self.target_namespace]: if schema_url == schema.url: logger.info("Resource %r is already loaded", location) break else: schema = type(self)( source=schema_url, namespace=self.target_namespace, validation=self.validation, global_maps=self.maps, converter=self.converter, locations=self._locations, base_url=self.base_url, allow=self.allow, defuse=self.defuse, timeout=self.timeout, build=build, ) if schema is self: return self elif location not in self.includes: self.includes[location] = schema elif self.includes[location] is not schema: self.includes[schema_url] = schema return schema def _parse_imports(self) -> None: """ Parse namespace import elements. Imports are done on namespace basis, not on single resource. A warning is generated for a failure of a namespace import. """ namespace_imports = NamespaceResourcesMap(map( lambda x: (x.get('namespace'), x.get('schemaLocation')), filter(lambda x: x.tag == XSD_IMPORT, self.source.root) )) for namespace, locations in namespace_imports.items(): # Checks the namespace against the targetNamespace of the schema if namespace is None: namespace = '' if namespace == self.target_namespace: self.parse_error("if the 'namespace' attribute is not present on " "the import statement then the importing schema " "must have a 'targetNamespace'") continue elif namespace == self.target_namespace: self.parse_error("the attribute 'namespace' must be different from " "schema's 'targetNamespace'") continue # Skip import of already imported namespaces if self.imports.get(namespace) is not None: continue elif namespace in self.maps.namespaces: self.imports[namespace] = self.maps.namespaces[namespace][0] continue locations = [url for url in locations if url] if not namespace: pass elif not locations: locations = self.get_locations(namespace) elif all(is_remote_url(url) for url in locations): # If all import schema locations are remote URLs and there are local hints # that match a local file path, try the local hints before schema locations. # This is not the standard processing for XSD imports, but resolve the problem # of local processing of schemas tested to work from a http server, providing # explicit local hints. local_hints = [url for url in self.get_locations(namespace) if url and url_path_is_file(url)] if local_hints: locations = local_hints + locations if namespace in self.fallback_locations: locations.append(self.fallback_locations[namespace]) self._import_namespace(namespace, locations) def _import_namespace(self, namespace: str, locations: List[str]) -> None: import_error = None for url in locations: try: logger.debug("Import namespace %r from %r", namespace, url) self.import_schema(namespace, url, self.base_url) except (OSError, IOError) as err: # It's not an error if the location access fails (ref. section 4.2.6.2): # https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#composition-schemaImport logger.debug('%s', err) if import_error is None: import_error = err except (XMLSchemaParseError, XMLSchemaTypeError, ParseError) as err: if namespace: msg = "cannot import namespace %r: %s." % (namespace, err) else: msg = "cannot import chameleon schema: %s." % err if isinstance(err, (XMLSchemaParseError, ParseError)): self.parse_error(msg) else: raise type(err)(msg) except XMLSchemaValueError as err: self.parse_error(err) else: logger.info("Namespace %r imported from %r", namespace, url) break else: if import_error is not None: msg = "Import of namespace {!r} from {!r} failed: {}." self.warnings.append(msg.format(namespace, locations, str(import_error))) warnings.warn(self.warnings[-1], XMLSchemaImportWarning, stacklevel=4) self.imports[namespace] = None def import_schema(self, namespace: str, location: str, base_url: Optional[str] = None, force: bool = False, build: bool = False) -> Optional[SchemaType]: """ Imports a schema for an external namespace, from a specific URL. :param namespace: is the URI of the external namespace. :param location: is the URL of the schema. :param base_url: is an optional base URL for fetching the schema resource. :param force: if set to `True` imports the schema also if the namespace is already imported. :param build: defines when to build the imported schema, the default is to not build. :return: the imported :class:`XMLSchema` instance. """ if location == self.url: return self if not force: if self.imports.get(namespace) is not None: return self.imports[namespace] elif namespace in self.maps.namespaces: self.imports[namespace] = self.maps.namespaces[namespace][0] return self.imports[namespace] schema: SchemaType schema_url = fetch_resource(location, base_url) imported_ns = self.imports.get(namespace) if imported_ns is not None and imported_ns.url == schema_url: return imported_ns elif namespace in self.maps.namespaces: for schema in self.maps.namespaces[namespace]: if schema_url == schema.url: self.imports[namespace] = schema return schema schema = type(self)( source=schema_url, validation=self.validation, global_maps=self.maps, converter=self.converter, locations=self._locations, base_url=self.base_url, allow=self.allow, defuse=self.defuse, timeout=self.timeout, build=build, ) if schema.target_namespace != namespace: raise XMLSchemaValueError( 'imported schema %r has an unmatched namespace %r' % (location, namespace) ) self.imports[namespace] = schema return schema def add_schema(self, source: SchemaSourceType, namespace: Optional[str] = None, build: bool = False) -> SchemaType: """ Add another schema source to the maps of the instance. :param source: an URI that reference to a resource or a file path or a file-like \ object or a string containing the schema or an Element or an ElementTree document. :param namespace: is an optional argument that contains the URI of the namespace \ that has to used in case the schema has no namespace (chameleon schema). For other \ cases, when specified, it must be equal to the *targetNamespace* of the schema. :param build: defines when to build the imported schema, the default is to not build. :return: the added :class:`XMLSchema` instance. """ return type(self)( source=source, namespace=namespace, validation=self.validation, global_maps=self.maps, converter=self.converter, locations=self._locations, base_url=self.base_url, allow=self.allow, defuse=self.defuse, timeout=self.timeout, build=build, ) def export(self, target: str, save_remote: bool = False) -> None: """ Exports a schema instance. The schema instance is exported to a directory with also the hierarchy of imported/included schemas. :param target: a path to a local empty directory. :param save_remote: if `True` is provided saves also remote schemas. """ import pathlib from urllib.parse import urlsplit target_path = pathlib.Path(target) if target_path.is_dir(): if list(target_path.iterdir()): raise XMLSchemaValueError("target directory {!r} is not empty".format(target)) elif target_path.exists(): msg = "target {} is not a directory" raise XMLSchemaValueError(msg.format(target_path.parent)) elif not target_path.parent.exists(): msg = "target parent directory {} does not exist" raise XMLSchemaValueError(msg.format(target_path.parent)) elif not target_path.parent.is_dir(): msg = "target parent {} is not a directory" raise XMLSchemaValueError(msg.format(target_path.parent)) url = self.url or 'schema.xsd' basename = pathlib.Path(urlsplit(url).path).name exports: Any = {self: [target_path.joinpath(basename), self.get_text()]} path: Any while True: current_length = len(exports) for schema in list(exports): dir_path = exports[schema][0].parent imports_items = [(x.url, x) for x in schema.imports.values() if x is not None] for location, ref_schema in chain(schema.includes.items(), imports_items): if ref_schema in exports: continue if is_remote_url(location): if not save_remote: continue url_parts = urlsplit(location) netloc, path = url_parts.netloc, url_parts.path path = pathlib.Path().joinpath(netloc).joinpath(path.lstrip('/')) else: if location.startswith('file:/'): location = urlsplit(location).path path = pathlib.Path(location) if path.is_absolute(): location = '/'.join(path.parts[-2:]) try: schema_path = pathlib.Path(schema.filepath) except TypeError: pass else: try: path = path.relative_to(schema_path.parent) except ValueError: parts = path.parts if parts[:-2] == schema_path.parts[:-2]: path = pathlib.Path(location) else: path = dir_path.joinpath(path) exports[ref_schema] = [path, ref_schema.get_text()] continue elif not str(path).startswith('..'): path = dir_path.joinpath(path) exports[ref_schema] = [path, ref_schema.get_text()] continue if DRIVE_PATTERN.match(path.parts[0]): path = pathlib.Path().joinpath(path.parts[1:]) for strip_path in ('/', '\\', '..'): while True: try: path = path.relative_to(strip_path) except ValueError: break path = target_path.joinpath(path) repl = 'schemaLocation="{}"'.format(path.as_posix()) schema_text = exports[schema][1] pattern = r'\bschemaLocation\s*=\s*[\'\"].*%s.*[\'"]' % re.escape(location) exports[schema][1] = re.sub(pattern, repl, schema_text) exports[ref_schema] = [path, ref_schema.get_text()] if current_length == len(exports): break for schema, (path, text) in exports.items(): if not path.parent.exists(): path.parent.mkdir(parents=True) with path.open(mode='w') as fp: fp.write(text) def version_check(self, elem: ElementType) -> bool: """ Checks if the element is compatible with the version of the validator and XSD types/facets availability. Invalid vc attributes are not detected in XSD 1.0. :param elem: an Element of the schema. :return: `True` if the schema element is compatible with the validator, \ `False` otherwise. """ if VC_MIN_VERSION in elem.attrib: vc_min_version = elem.attrib[VC_MIN_VERSION] if not XSD_VERSION_PATTERN.match(vc_min_version): if self.XSD_VERSION > '1.0': self.parse_error("invalid attribute vc:minVersion value", elem) elif vc_min_version > self.XSD_VERSION: return False if VC_MAX_VERSION in elem.attrib: vc_max_version = elem.attrib[VC_MAX_VERSION] if not XSD_VERSION_PATTERN.match(vc_max_version): if self.XSD_VERSION > '1.0': self.parse_error("invalid attribute vc:maxVersion value", elem) elif vc_max_version <= self.XSD_VERSION: return False if VC_TYPE_AVAILABLE in elem.attrib: for qname in elem.attrib[VC_TYPE_AVAILABLE].split(): try: if self.resolve_qname(qname) not in self.maps.types: return False except XMLSchemaNamespaceError: return False except (KeyError, ValueError) as err: self.parse_error(str(err), elem) if VC_TYPE_UNAVAILABLE in elem.attrib: for qname in elem.attrib[VC_TYPE_UNAVAILABLE].split(): try: if self.resolve_qname(qname) not in self.maps.types: break except XMLSchemaNamespaceError: break except (KeyError, ValueError) as err: self.parse_error(err, elem) else: return False if VC_FACET_AVAILABLE in elem.attrib: for qname in elem.attrib[VC_FACET_AVAILABLE].split(): try: facet_name = self.resolve_qname(qname) except XMLSchemaNamespaceError: pass except (KeyError, ValueError) as err: self.parse_error(str(err), elem) else: if self.XSD_VERSION == '1.0': if facet_name not in XSD_10_FACETS: return False elif facet_name not in XSD_11_FACETS: return False if VC_FACET_UNAVAILABLE in elem.attrib: for qname in elem.attrib[VC_FACET_UNAVAILABLE].split(): try: facet_name = self.resolve_qname(qname) except XMLSchemaNamespaceError: break except (KeyError, ValueError) as err: self.parse_error(err, elem) else: if self.XSD_VERSION == '1.0': if facet_name not in XSD_10_FACETS: break elif facet_name not in XSD_11_FACETS: break else: return False return True def resolve_qname(self, qname: str, namespace_imported: bool = True) -> str: """ QName resolution for a schema instance. :param qname: a string in xs:QName format. :param namespace_imported: if this argument is `True` raises an \ `XMLSchemaNamespaceError` if the namespace of the QName is not the \ *targetNamespace* and the namespace is not imported by the schema. :returns: an expanded QName in the format "{*namespace-URI*}*local-name*". :raises: `XMLSchemaValueError` for an invalid xs:QName is found, \ `XMLSchemaKeyError` if the namespace prefix is not declared in the \ schema instance. """ qname = qname.strip() if not qname or ' ' in qname or '\t' in qname or '\n' in qname: raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) if qname[0] == '{': try: namespace, local_name = qname[1:].split('}') except ValueError: raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) elif ':' in qname: try: prefix, local_name = qname.split(':') except ValueError: raise XMLSchemaValueError("{!r} is not a valid value for xs:QName".format(qname)) else: try: namespace = self.namespaces[prefix] except KeyError: raise XMLSchemaKeyError("prefix %r not found in namespace map" % prefix) else: namespace, local_name = self.namespaces.get('', ''), qname if not namespace: if namespace_imported and self.target_namespace and '' not in self.imports: raise XMLSchemaNamespaceError( "the QName {!r} is mapped to no namespace, but this requires " "that there is an xs:import statement in the schema without " "the 'namespace' attribute.".format(qname) ) return local_name elif namespace_imported and self.meta_schema is not None and \ namespace != self.target_namespace and \ namespace not in {XSD_NAMESPACE, XSI_NAMESPACE} and \ namespace not in self.imports: raise XMLSchemaNamespaceError( "the QName {!r} is mapped to the namespace {!r}, but this namespace has " "not an xs:import statement in the schema.".format(qname, namespace) ) return '{%s}%s' % (namespace, local_name) def validate(self, source: Union[XMLSourceType, XMLResource], path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> None: """ Validates an XML data against the XSD schema/component instance. :param source: the source of XML data. Can be an :class:`XMLResource` instance, a \ path to a file or an URI of a resource or an opened file-like object or an Element \ instance or an ElementTree instance or a string containing the XML data. :param path: is an optional XPath expression that matches the elements of the XML \ data that have to be decoded. If not provided the XML root element is selected. :param schema_path: an alternative XPath expression to select the XSD element \ to use for decoding. Useful if the root of the XML data doesn't match an XSD \ global element of the schema. :param use_defaults: Use schema's default values for filling missing data. :param namespaces: is an optional mapping from namespace prefix to URI. :param max_depth: maximum level of validation, for default there is no limit. \ With lazy resources is set to `source.lazy_depth` for managing lazy validation. :param extra_validator: an optional function for performing non-standard \ validations on XML data. The provided function is called for each traversed \ element, with the XML element as 1st argument and the corresponding XSD \ element as 2nd argument. It can be also a generator function and has to \ raise/yield :exc:`XMLSchemaValidationError` exceptions. :raises: :exc:`XMLSchemaValidationError` if the XML data instance is invalid. """ for error in self.iter_errors(source, path, schema_path, use_defaults, namespaces, max_depth, extra_validator): raise error def is_valid(self, source: Union[XMLSourceType, XMLResource], path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> bool: """ Like :meth:`validate` except that does not raise an exception but returns ``True`` if the XML data instance is valid, ``False`` if it is invalid. """ error = next(self.iter_errors(source, path, schema_path, use_defaults, namespaces, max_depth, extra_validator), None) return error is None def iter_errors(self, source: Union[XMLSourceType, XMLResource], path: Optional[str] = None, schema_path: Optional[str] = None, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) \ -> Iterator[XMLSchemaValidationError]: """ Creates an iterator for the errors generated by the validation of an XML data against the XSD schema/component instance. Accepts the same arguments of :meth:`validate`. """ self.check_validator(validation='lax') if isinstance(source, XMLResource): resource: XMLResource = source else: resource = XMLResource(source, defuse=self.defuse, timeout=self.timeout) if not schema_path: schema_path = resource.get_absolute_path(path) namespaces = resource.get_namespaces(namespaces, root_only=True) namespace = resource.namespace or namespaces.get('', '') try: schema = self.get_schema(namespace) except KeyError: schema = self identities: Dict[XsdIdentity, IdentityCounter] = {} locations: List[Any] = [] ancestors: List[ElementType] = [] prev_ancestors: List[ElementType] = [] kwargs: Dict[Any, Any] = { 'level': resource.lazy_depth or bool(path), 'source': resource, 'namespaces': namespaces, 'converter': None, 'use_defaults': use_defaults, 'id_map': Counter[str](), 'identities': identities, 'inherited': {}, 'locations': locations, # TODO: lazy schemas load } if max_depth is not None: kwargs['max_depth'] = max_depth if extra_validator is not None: kwargs['extra_validator'] = extra_validator if path: selector = resource.iterfind(path, namespaces, nsmap=namespaces, ancestors=ancestors) else: selector = resource.iter_depth(mode=3, nsmap=namespaces, ancestors=ancestors) for elem in selector: if elem is resource.root: xsd_element = schema.get_element(elem.tag, namespaces=namespaces) if resource.lazy_depth: kwargs['level'] = 0 kwargs['identities'] = {} kwargs['max_depth'] = resource.lazy_depth else: if prev_ancestors != ancestors: k = 0 for k in range(min(len(ancestors), len(prev_ancestors))): if ancestors[k] is not prev_ancestors[k]: break path_ = '/'.join(e.tag for e in ancestors) + '/ancestor-or-self::node()' xsd_ancestors = cast(List[XsdElement], schema.findall(path_, namespaces)[1:]) for e in xsd_ancestors[k:]: e.stop_identities(identities) for e in xsd_ancestors[k:]: e.start_identities(identities) prev_ancestors = ancestors[:] xsd_element = schema.get_element(elem.tag, schema_path, namespaces) if xsd_element is None: if XSI_TYPE in elem.attrib: xsd_element = self.create_element(name=elem.tag) elif elem is not resource.root and ancestors: continue else: reason = "{!r} is not an element of the schema".format(elem) yield schema.validation_error('lax', reason, elem, resource, namespaces) return for result in xsd_element.iter_decode(elem, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: del result if kwargs['identities'] is not identities: identity: XsdIdentity counter: IdentityCounter for identity, counter in kwargs['identities'].items(): identities[identity].counter.update(counter.counter) kwargs['identities'] = identities yield from self._validate_references(validation='lax', **kwargs) def _validate_references(self, source: XMLResource, validation: str = 'lax', id_map: Optional[Counter[str]] = None, identities: Optional[IdentityMapType] = None, **kwargs: Any) -> Iterator[XMLSchemaValidationError]: # Check unresolved IDREF values if id_map is not None: for k, v in id_map.items(): if v == 0: msg = "IDREF %r not found in XML document" % k yield self.validation_error(validation, msg, source.root) # Check still enabled key references (lazy validation cases) if identities is not None: for constraint, counter in identities.items(): if counter.enabled and isinstance(constraint, XsdKeyref): for error in cast(KeyrefCounter, counter).iter_errors(identities): yield self.validation_error(validation, error, source.root, **kwargs) def raw_decoder(self, source: XMLResource, path: Optional[str] = None, schema_path: Optional[str] = None, validation: str = 'lax', namespaces: Optional[NamespacesType] = None, **kwargs: Any) \ -> Iterator[Union[Any, XMLSchemaValidationError]]: """Returns a generator for decoding a resource.""" if path: selector = source.iterfind(path, namespaces, nsmap=namespaces) else: selector = source.iter_depth(nsmap=namespaces) for elem in selector: xsd_element = self.get_element(elem.tag, schema_path, namespaces) if xsd_element is None: if XSI_TYPE in elem.attrib: xsd_element = self.create_element(name=elem.tag) else: reason = "{!r} is not an element of the schema".format(elem) yield self.validation_error(validation, reason, elem, source, namespaces) continue yield from xsd_element.iter_decode(elem, validation, **kwargs) if 'max_depth' not in kwargs: yield from self._validate_references(source, validation=validation, **kwargs) def iter_decode(self, source: Union[XMLSourceType, XMLResource], path: Optional[str] = None, schema_path: Optional[str] = None, validation: str = 'lax', process_namespaces: bool = True, namespaces: Optional[NamespacesType] = None, use_defaults: bool = True, decimal_type: Optional[Type[Any]] = None, datetime_types: bool = False, binary_types: bool = False, converter: Optional[ConverterType] = None, filler: Optional[Callable[[Union[XsdElement, XsdAttribute]], Any]] = None, fill_missing: bool = False, keep_unknown: bool = False, process_skipped: bool = False, max_depth: Optional[int] = None, depth_filler: Optional[Callable[[XsdElement], Any]] = None, value_hook: Optional[Callable[[AtomicValueType, BaseXsdType], Any]] = None, **kwargs: Any) -> Iterator[Union[Any, XMLSchemaValidationError]]: """ Creates an iterator for decoding an XML source to a data structure. :param source: the source of XML data. Can be an :class:`XMLResource` instance, a \ path to a file or an URI of a resource or an opened file-like object or an Element \ instance or an ElementTree instance or a string containing the XML data. :param path: is an optional XPath expression that matches the elements of the XML \ data that have to be decoded. If not provided the XML root element is selected. :param schema_path: an alternative XPath expression to select the XSD element \ to use for decoding. Useful if the root of the XML data doesn't match an XSD \ global element of the schema. :param validation: defines the XSD validation mode to use for decode, can be \ 'strict', 'lax' or 'skip'. :param process_namespaces: whether to use namespace information in the \ decoding process, using the map provided with the argument *namespaces* \ and the map extracted from the XML document. :param namespaces: is an optional mapping from namespace prefix to URI. :param use_defaults: whether to use default values for filling missing data. :param decimal_type: conversion type for `Decimal` objects (generated by \ `xs:decimal` built-in and derived types), useful if you want to generate a \ JSON-compatible data structure. :param datetime_types: if set to `True` the datetime and duration XSD types \ are kept decoded, otherwise their origin XML string is returned. :param binary_types: if set to `True` xs:hexBinary and xs:base64Binary types \ are kept decoded, otherwise their origin XML string is returned. :param converter: an :class:`XMLSchemaConverter` subclass or instance to use \ for decoding. :param filler: an optional callback function to fill undecodable data with a \ typed value. The callback function must accept one positional argument, that \ can be an XSD Element or an attribute declaration. If not provided undecodable \ data is replaced by `None`. :param fill_missing: if set to `True` the decoder fills also missing attributes. \ The filling value is `None` or a typed value if the *filler* callback is provided. :param keep_unknown: if set to `True` unknown tags are kept and are decoded with \ *xs:anyType*. For default unknown tags not decoded by a wildcard are discarded. :param process_skipped: process XML data that match a wildcard with \ `processContents='skip'`. :param max_depth: maximum level of decoding, for default there is no limit. \ With lazy resources is set to `source.lazy_depth` for managing lazy decoding. :param depth_filler: an optional callback function to replace data over the \ *max_depth* level. The callback function must accept one positional argument, that \ can be an XSD Element. If not provided deeper data are replaced with `None` values. :param value_hook: an optional function that will be called with any decoded \ atomic value and the XSD type used for decoding. The return value will be used \ instead of the original value. :param kwargs: keyword arguments with other options for converter and decoder. :return: yields a decoded data object, eventually preceded by a sequence of \ validation or decoding errors. """ self.check_validator(validation) if isinstance(source, XMLResource): resource: XMLResource = source else: resource = XMLResource(source, defuse=self.defuse, timeout=self.timeout) if not schema_path and path: schema_path = resource.get_absolute_path(path) if process_namespaces: namespaces = resource.get_namespaces(namespaces, root_only=True) namespace = resource.namespace or namespaces.get('', '') else: namespace = resource.namespace schema = self.get_schema(namespace) converter = self.get_converter(converter, namespaces=namespaces, **kwargs) kwargs.update( converter=converter, namespaces=namespaces, source=resource, use_defaults=use_defaults, id_map=Counter[str](), identities={}, inherited={}, ) if decimal_type is not None: kwargs['decimal_type'] = decimal_type if datetime_types: kwargs['datetime_types'] = datetime_types if binary_types: kwargs['binary_types'] = binary_types if filler is not None: kwargs['filler'] = filler if fill_missing: kwargs['fill_missing'] = fill_missing if keep_unknown: kwargs['keep_unknown'] = keep_unknown if process_skipped: kwargs['process_skipped'] = process_skipped if max_depth is not None: kwargs['max_depth'] = max_depth if depth_filler is not None: kwargs['depth_filler'] = depth_filler if value_hook is not None: kwargs['value_hook'] = value_hook if path: selector = resource.iterfind(path, namespaces, nsmap=namespaces) elif not resource.is_lazy(): selector = resource.iter_depth(nsmap=namespaces) else: decoder = self.raw_decoder( schema_path=resource.get_absolute_path(), validation=validation, **kwargs ) kwargs['depth_filler'] = lambda x: decoder kwargs['max_depth'] = resource.lazy_depth selector = resource.iter_depth(mode=2, nsmap=namespaces) for elem in selector: xsd_element = schema.get_element(elem.tag, schema_path, namespaces) if xsd_element is None: if XSI_TYPE in elem.attrib: xsd_element = self.create_element(name=elem.tag) else: reason = "{!r} is not an element of the schema".format(elem) yield schema.validation_error(validation, reason, elem, resource, namespaces) return yield from xsd_element.iter_decode(elem, validation, **kwargs) if 'max_depth' not in kwargs: yield from self._validate_references(validation=validation, **kwargs) def decode(self, source: Union[XMLSourceType, XMLResource], path: Optional[str] = None, schema_path: Optional[str] = None, validation: str = 'strict', *args: Any, **kwargs: Any) -> DecodeType[Any]: """ Decodes XML data. Takes the same arguments of the method :func:`XMLSchema.iter_decode`. """ data, errors = [], [] for result in self.iter_decode(source, path, schema_path, validation, *args, **kwargs): if not isinstance(result, XMLSchemaValidationError): data.append(result) elif validation == 'lax': errors.append(result) elif validation == 'strict': raise result if not data: return (None, errors) if validation == 'lax' else None elif len(data) == 1: return (data[0], errors) if validation == 'lax' else data[0] else: return (data, errors) if validation == 'lax' else data to_dict = decode def to_objects(self, source: Union[XMLSourceType, XMLResource], with_bindings: bool = False, **kwargs: Any) -> DecodeType['dataobjects.DataElement']: """ Decodes XML data to Python data objects. :param source: the XML data. Can be a string for an attribute or for a simple \ type components or a dictionary for an attribute group or an ElementTree's \ Element for other components. :param with_bindings: if `True` is provided the decoding is done using \ :class:`DataBindingConverter` that used XML data binding classes. For \ default the objects are instances of :class:`DataElement` and uses the \ :class:`DataElementConverter`. :param kwargs: other optional keyword arguments for the method \ :func:`iter_decode`, except the argument *converter*. """ if with_bindings: return self.decode(source, converter=dataobjects.DataBindingConverter, **kwargs) return self.decode(source, converter=dataobjects.DataElementConverter, **kwargs) def iter_encode(self, obj: Any, path: Optional[str] = None, validation: str = 'lax', namespaces: Optional[NamespacesType] = None, use_defaults: bool = True, converter: Optional[ConverterType] = None, unordered: bool = False, **kwargs: Any) -> Iterator[Union[ElementType, XMLSchemaValidationError]]: """ Creates an iterator for encoding a data structure to an ElementTree's Element. :param obj: the data that has to be encoded to XML data. :param path: is an optional XPath expression for selecting the element of \ the schema that matches the data that has to be encoded. For default the first \ global element of the schema is used. :param validation: the XSD validation mode. Can be 'strict', 'lax' or 'skip'. :param namespaces: is an optional mapping from namespace prefix to URI. :param use_defaults: whether to use default values for filling missing data. :param converter: an :class:`XMLSchemaConverter` subclass or instance to use for \ the encoding. :param unordered: a flag for explicitly activating unordered encoding mode for \ content model data. This mode uses content models for a reordered-by-model \ iteration of the child elements. :param kwargs: keyword arguments with other options for encoding and for \ building the converter instance. :return: yields an Element instance/s or validation/encoding errors. """ self.check_validator(validation) if not self.elements: raise XMLSchemaValueError("encoding needs at least one XSD element declaration!") if namespaces is None: namespaces = {} else: namespaces = {k: v for k, v in namespaces.items()} converter = self.get_converter(converter, namespaces=namespaces, **kwargs) xsd_element = None if path is not None: match = re.search(r'[{\w]', path) if match: namespace = get_namespace(path[match.start():], namespaces) schema = self.get_schema(namespace) xsd_element = schema.find(path, namespaces) elif len(self.elements) == 1: xsd_element = list(self.elements.values())[0] else: root_elements = self.root_elements if len(root_elements) == 1: xsd_element = root_elements[0] elif isinstance(obj, (converter.dict, dict)) and len(obj) == 1: for key in obj: match = re.search(r'[{\w]', key) if match: namespace = get_namespace(key[match.start():], namespaces) schema = self.get_schema(namespace) xsd_element = schema.find(key, namespaces) if not isinstance(xsd_element, XsdElement): if path is not None: reason = "the path %r doesn't match any element of the schema!" % path else: reason = "unable to select an element for decoding data, " \ "provide a valid 'path' argument." raise XMLSchemaEncodeError(self, obj, self.elements, reason, namespaces=namespaces) else: yield from xsd_element.iter_encode(obj, validation, use_defaults=use_defaults, converter=converter, unordered=unordered, **kwargs) def encode(self, obj: Any, path: Optional[str] = None, validation: str = 'strict', *args: Any, **kwargs: Any) -> EncodeType[Any]: """ Encodes to XML data. Takes the same arguments of the method :func:`XMLSchema.iter_encode`. :return: An ElementTree's Element or a list containing a sequence of ElementTree's \ elements if the argument *path* matches multiple XML data chunks. If *validation* \ argument is 'lax' a 2-items tuple is returned, where the first item is the encoded \ object and the second item is a list containing the errors. """ data, errors = [], [] result: Union[ElementType, XMLSchemaValidationError] for result in self.iter_encode(obj, path, validation, *args, **kwargs): if not isinstance(result, XMLSchemaValidationError): data.append(result) elif validation == 'lax': errors.append(result) elif validation == 'strict': raise result if not data: return (None, errors) if validation == 'lax' else None elif len(data) == 1: if errors: resource = XMLResource(data[0]) for e in errors: e.source = resource return (data[0], errors) if validation == 'lax' else data[0] else: return (data, errors) if validation == 'lax' else data to_etree = encode class XMLSchema10(XMLSchemaBase): """ XSD 1.0 schema class. <schema attributeFormDefault = (qualified | unqualified) : unqualified blockDefault = (#all | List of (extension | restriction | substitution)) : '' elementFormDefault = (qualified | unqualified) : unqualified finalDefault = (#all | List of (extension | restriction | list | union)) : '' id = ID targetNamespace = anyURI version = token xml:lang = language {any attributes with non-schema namespace . . .}> Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*) </schema> """ meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.0/XMLSchema.xsd') # type: ignore BASE_SCHEMAS = { XML_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XML/xml_minimal.xsd'), XSI_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSI/XMLSchema-instance_minimal.xsd'), } class XMLSchema11(XMLSchemaBase): """ XSD 1.1 schema class. <schema attributeFormDefault = (qualified | unqualified) : unqualified blockDefault = (#all | List of (extension | restriction | substitution)) : '' defaultAttributes = QName xpathDefaultNamespace = (anyURI | (##defaultNamespace | ##targetNamespace| ##local)) : ##local elementFormDefault = (qualified | unqualified) : unqualified finalDefault = (#all | List of (extension | restriction | list | union)) : '' id = ID targetNamespace = anyURI version = token xml:lang = language {any attributes with non-schema namespace . . .}> Content: ((include | import | redefine | override | annotation)*, (defaultOpenContent, annotation*)?, ((simpleType | complexType | group | attributeGroup | element | attribute | notation), annotation*)*) </schema> <schema attributeFormDefault = (qualified | unqualified) : unqualified blockDefault = (#all | List of (extension | restriction | substitution)) : '' elementFormDefault = (qualified | unqualified) : unqualified finalDefault = (#all | List of (extension | restriction | list | union)) : '' id = ID targetNamespace = anyURI version = token xml:lang = language {any attributes with non-schema namespace . . .}> Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*) </schema> """ meta_schema = os.path.join(SCHEMAS_DIR, 'XSD_1.1/XMLSchema.xsd') # type: ignore XSD_VERSION = '1.1' BASE_SCHEMAS = { XML_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XML/xml_minimal.xsd'), XSI_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSI/XMLSchema-instance_minimal.xsd'), XSD_NAMESPACE: os.path.join(SCHEMAS_DIR, 'XSD_1.1/xsd11-extra.xsd'), VC_NAMESPACE: os.path.join(SCHEMAS_DIR, 'VC/XMLSchema-versioning.xsd'), } xsd_complex_type_class = Xsd11ComplexType xsd_attribute_class = Xsd11Attribute xsd_any_attribute_class = Xsd11AnyAttribute xsd_group_class = Xsd11Group xsd_element_class = Xsd11Element xsd_any_class = Xsd11AnyElement xsd_atomic_restriction_class = Xsd11AtomicRestriction xsd_union_class = Xsd11Union xsd_key_class = Xsd11Key xsd_keyref_class = Xsd11Keyref xsd_unique_class = Xsd11Unique XMLSchema = XMLSchema10 """The default class for schema instances.""" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/simple_types.py�����������������������������������������������0000664�0000000�0000000�00000166226�14211403446�0023006�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for XML Schema simple data types. """ from decimal import DecimalException from typing import cast, Any, Callable, Dict, Iterator, List, \ Optional, Set, Union, Tuple, Type from ..etree import etree_element from ..aliases import ElementType, AtomicValueType, ComponentClassType, \ IterDecodeType, IterEncodeType, BaseXsdType, SchemaType, DecodedValueType, \ EncodedValueType from ..exceptions import XMLSchemaTypeError, XMLSchemaValueError from ..names import XSD_NAMESPACE, XSD_ANY_TYPE, XSD_SIMPLE_TYPE, XSD_PATTERN, \ XSD_ANY_ATOMIC_TYPE, XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE, \ XSD_MIN_INCLUSIVE, XSD_MIN_EXCLUSIVE, XSD_MAX_INCLUSIVE, XSD_MAX_EXCLUSIVE, \ XSD_LENGTH, XSD_MIN_LENGTH, XSD_MAX_LENGTH, XSD_WHITE_SPACE, XSD_ENUMERATION,\ XSD_LIST, XSD_ANY_SIMPLE_TYPE, XSD_UNION, XSD_RESTRICTION, XSD_ANNOTATION, \ XSD_ASSERTION, XSD_ID, XSD_IDREF, XSD_FRACTION_DIGITS, XSD_TOTAL_DIGITS, \ XSD_EXPLICIT_TIMEZONE, XSD_ERROR, XSD_ASSERT, XSD_QNAME, XSD_UNTYPED_ATOMIC from ..helpers import get_prefixed_qname, local_name from .exceptions import XMLSchemaValidationError, XMLSchemaEncodeError, \ XMLSchemaDecodeError, XMLSchemaParseError from .xsdbase import XsdComponent, XsdType, ValidationMixin from .facets import XsdFacet, XsdWhiteSpaceFacet, XsdPatternFacets, \ XsdEnumerationFacets, XsdAssertionFacet, XSD_10_FACETS_BUILDERS, \ XSD_11_FACETS_BUILDERS, XSD_10_FACETS, XSD_11_FACETS, XSD_10_LIST_FACETS, \ XSD_11_LIST_FACETS, XSD_10_UNION_FACETS, XSD_11_UNION_FACETS, MULTIPLE_FACETS FacetsValueType = Union[XsdFacet, Callable[[Any], None], List[XsdAssertionFacet]] PythonTypeClasses = Type[Any] class XsdSimpleType(XsdType, ValidationMixin[Union[str, bytes], DecodedValueType]): """ Base class for simpleTypes definitions. Generally used only for instances of xs:anySimpleType. .. <simpleType final = (#all | List of (list | union | restriction | extension)) id = ID name = NCName {any attributes with non-schema namespace . . .}> Content: (annotation?, (restriction | list | union)) </simpleType> """ _special_types = {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE} _ADMITTED_TAGS = {XSD_SIMPLE_TYPE} copy: Callable[['XsdSimpleType'], 'XsdSimpleType'] block: str = '' min_length: Optional[int] = None max_length: Optional[int] = None white_space: Optional[str] = None patterns = None validators: Union[Tuple[()], List[Union[XsdFacet, Callable[[Any], None]]]] = () allow_empty = True facets: Dict[Optional[str], FacetsValueType] python_type: PythonTypeClasses instance_types: Union[PythonTypeClasses, Tuple[PythonTypeClasses]] # Unicode string as default datatype for XSD simple types python_type = instance_types = to_python = from_python = str def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent] = None, name: Optional[str] = None, facets: Optional[Dict[Optional[str], FacetsValueType]] = None) -> None: super(XsdSimpleType, self).__init__(elem, schema, parent, name) if not hasattr(self, 'facets'): self.facets = facets if facets is not None else {} def __setattr__(self, name: str, value: Any) -> None: super(XsdSimpleType, self).__setattr__(name, value) if name == 'facets': if not isinstance(self, XsdAtomicBuiltin): self._parse_facets(value) if self.min_length: self.allow_empty = False white_space = getattr(self.get_facet(XSD_WHITE_SPACE), 'value', None) if white_space is not None: self.white_space = white_space patterns = self.get_facet(XSD_PATTERN) if isinstance(patterns, XsdPatternFacets): self.patterns = patterns if all(p.match('') is None for p in patterns.patterns): self.allow_empty = False enumeration = self.get_facet(XSD_ENUMERATION) if isinstance(enumeration, XsdEnumerationFacets) \ and '' not in enumeration.enumeration: self.allow_empty = False if value: validators: List[Union[XsdFacet, Callable[[Any], None]]] if None in value: validators = [value[None]] # Use only the validator function! else: validators = [v for k, v in value.items() if k not in {XSD_WHITE_SPACE, XSD_PATTERN, XSD_ASSERTION}] if XSD_ASSERTION in value: assertions: Union[XsdAssertionFacet, List[XsdAssertionFacet]] assertions = value[XSD_ASSERTION] if isinstance(assertions, list): validators.extend(assertions) else: validators.append(assertions) if validators: self.validators = validators def _parse_facets(self, facets: Any) -> None: base_type: Any if facets and self.base_type is not None: if isinstance(self.base_type, XsdSimpleType): if self.base_type.name == XSD_ANY_SIMPLE_TYPE: self.parse_error( "facets not allowed for a direct derivation of xs:anySimpleType" ) elif self.base_type.has_simple_content(): if self.base_type.content.name == XSD_ANY_SIMPLE_TYPE: self.parse_error( "facets not allowed for a direct content derivation of xs:anySimpleType" ) # Checks the applicability of the facets if any(k not in self.admitted_facets for k in facets if k is not None): reason = "one or more facets are not applicable, admitted set is %r:" self.parse_error(reason % {local_name(e) for e in self.admitted_facets if e}) # Check group base_type base_type = {t.base_type for t in facets.values() if isinstance(t, XsdFacet)} if len(base_type) > 1: self.parse_error("facet group must have the same base_type: %r" % base_type) base_type = base_type.pop() if base_type else None # Checks length based facets length = getattr(facets.get(XSD_LENGTH), 'value', None) min_length = getattr(facets.get(XSD_MIN_LENGTH), 'value', None) max_length = getattr(facets.get(XSD_MAX_LENGTH), 'value', None) if length is not None: if length < 0: self.parse_error("'length' value must be non negative integer") if min_length is not None: if min_length > length: self.parse_error("'minLength' value must be less or equal to 'length'") min_length_facet = base_type.get_facet(XSD_MIN_LENGTH) length_facet = base_type.get_facet(XSD_LENGTH) if (min_length_facet is None or (length_facet is not None and length_facet.base_type == min_length_facet.base_type)): self.parse_error("cannot specify both 'length' and 'minLength'") if max_length is not None: if max_length < length: self.parse_error("'maxLength' value must be greater or equal to 'length'") max_length_facet = base_type.get_facet(XSD_MAX_LENGTH) length_facet = base_type.get_facet(XSD_LENGTH) if max_length_facet is None \ or (length_facet is not None and length_facet.base_type == max_length_facet.base_type): self.parse_error("cannot specify both 'length' and 'maxLength'") min_length = max_length = length elif min_length is not None or max_length is not None: min_length_facet = base_type.get_facet(XSD_MIN_LENGTH) max_length_facet = base_type.get_facet(XSD_MAX_LENGTH) if min_length is not None: if min_length < 0: self.parse_error("'minLength' value must be non negative integer") if max_length is not None and max_length < min_length: self.parse_error("'maxLength' value is lesser than 'minLength'") if min_length_facet is not None and min_length_facet.value > min_length: self.parse_error("'minLength' has a lesser value than parent") if max_length_facet is not None and min_length > max_length_facet.value: self.parse_error("'minLength' has a greater value than parent 'maxLength'") if max_length is not None: if max_length < 0: self.parse_error("'maxLength' value mu st be non negative integer") if min_length_facet is not None and min_length_facet.value > max_length: self.parse_error("'maxLength' has a lesser value than parent 'minLength'") if max_length_facet is not None and max_length > max_length_facet.value: self.parse_error("'maxLength' has a greater value than parent") # Checks min/max values min_inclusive = getattr(facets.get(XSD_MIN_INCLUSIVE), 'value', None) min_exclusive = getattr(facets.get(XSD_MIN_EXCLUSIVE), 'value', None) max_inclusive = getattr(facets.get(XSD_MAX_INCLUSIVE), 'value', None) max_exclusive = getattr(facets.get(XSD_MAX_EXCLUSIVE), 'value', None) if min_inclusive is not None: if min_exclusive is not None: self.parse_error("cannot specify both 'minInclusive' and 'minExclusive") if max_inclusive is not None and min_inclusive > max_inclusive: self.parse_error("'minInclusive' must be less or equal to 'maxInclusive'") elif max_exclusive is not None and min_inclusive >= max_exclusive: self.parse_error("'minInclusive' must be lesser than 'maxExclusive'") elif min_exclusive is not None: if max_inclusive is not None and min_exclusive >= max_inclusive: self.parse_error("'minExclusive' must be lesser than 'maxInclusive'") elif max_exclusive is not None and min_exclusive > max_exclusive: self.parse_error("'minExclusive' must be less or equal to 'maxExclusive'") if max_inclusive is not None and max_exclusive is not None: self.parse_error("cannot specify both 'maxInclusive' and 'maxExclusive") # Checks fraction digits if XSD_TOTAL_DIGITS in facets: if XSD_FRACTION_DIGITS in facets and \ facets[XSD_TOTAL_DIGITS].value < facets[XSD_FRACTION_DIGITS].value: self.parse_error("fractionDigits facet value cannot be lesser than the " "value of totalDigits facet") total_digits = base_type.get_facet(XSD_TOTAL_DIGITS) if total_digits is not None and total_digits.value < facets[XSD_TOTAL_DIGITS].value: self.parse_error("totalDigits facet value cannot be greater than " "the value of the same facet in the base type") # Checks XSD 1.1 facets if XSD_EXPLICIT_TIMEZONE in facets: explicit_tz_facet = base_type.get_facet(XSD_EXPLICIT_TIMEZONE) if explicit_tz_facet and explicit_tz_facet.value in ('prohibited', 'required') \ and facets[XSD_EXPLICIT_TIMEZONE].value != explicit_tz_facet.value: self.parse_error("the explicitTimezone facet value cannot be changed if the base " "type has the same facet with value %r" % explicit_tz_facet.value) self.min_length = min_length self.max_length = max_length @property def variety(self) -> Optional[str]: return None @property def simple_type(self) -> 'XsdSimpleType': return self @property def min_value(self) -> Optional[AtomicValueType]: min_exclusive: Optional['AtomicValueType'] min_inclusive: Optional['AtomicValueType'] min_exclusive = cast( Optional['AtomicValueType'], getattr(self.get_facet(XSD_MIN_EXCLUSIVE), 'value', None) ) min_inclusive = cast( Optional['AtomicValueType'], getattr(self.get_facet(XSD_MIN_INCLUSIVE), 'value', None) ) if min_exclusive is None: return min_inclusive elif min_inclusive is None: return min_exclusive elif min_inclusive <= min_exclusive: # type: ignore[operator] return min_exclusive else: return min_inclusive @property def max_value(self) -> Optional[AtomicValueType]: max_exclusive: Optional['AtomicValueType'] max_inclusive: Optional['AtomicValueType'] max_exclusive = cast( Optional['AtomicValueType'], getattr(self.get_facet(XSD_MAX_EXCLUSIVE), 'value', None) ) max_inclusive = cast( Optional['AtomicValueType'], getattr(self.get_facet(XSD_MAX_INCLUSIVE), 'value', None) ) if max_exclusive is None: return max_inclusive elif max_inclusive is None: return max_exclusive elif max_inclusive >= max_exclusive: # type: ignore[operator] return max_exclusive else: return max_inclusive @property def enumeration(self) -> Optional[List[Optional[AtomicValueType]]]: enumeration = self.get_facet(XSD_ENUMERATION) if isinstance(enumeration, XsdEnumerationFacets): return enumeration.enumeration return None @property def admitted_facets(self) -> Set[str]: return XSD_10_FACETS if self.xsd_version == '1.0' else XSD_11_FACETS @property def built(self) -> bool: return True @staticmethod def is_simple() -> bool: return True @staticmethod def is_complex() -> bool: return False @property def content_type_label(self) -> str: return 'empty' if self.max_length == 0 else 'simple' @property def sequence_type(self) -> str: if self.is_empty(): return 'empty-sequence()' root_type = self.root_type if root_type.name is not None: sequence_type = cast(str, root_type.prefixed_name) else: sequence_type = get_prefixed_qname(XSD_UNTYPED_ATOMIC, self.namespaces) if not self.is_list(): return sequence_type elif self.is_emptiable(): return '{}*'.format(sequence_type) else: return '{}+'.format(sequence_type) def is_empty(self) -> bool: return self.max_length == 0 or \ self.enumeration is not None and all(v == '' for v in self.enumeration) def is_emptiable(self) -> bool: return self.allow_empty def has_simple_content(self) -> bool: return self.max_length != 0 def has_complex_content(self) -> bool: return False def has_mixed_content(self) -> bool: return False def is_element_only(self) -> bool: return False def is_derived(self, other: Union[BaseXsdType, Tuple[ElementType, SchemaType]], derivation: Optional[str] = None) -> bool: if self is other: return True elif isinstance(other, tuple): other[1].parse_error(f"global type {other[0].tag!r} is not built") return False elif derivation and self.derivation and derivation != self.derivation: return False elif other.name in self._special_types: return derivation != 'extension' elif self.base_type is other: return True elif self.base_type is None: if isinstance(other, XsdUnion): return any(self.is_derived(m, derivation) for m in other.member_types) return False elif self.base_type.is_complex(): if not self.base_type.has_simple_content(): return False return self.base_type.content.is_derived(other, derivation) # type: ignore elif isinstance(other, XsdUnion): return any(self.is_derived(m, derivation) for m in other.member_types) else: return self.base_type.is_derived(other, derivation) def is_dynamic_consistent(self, other: BaseXsdType) -> bool: return other.name in {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE} or self.is_derived(other) or \ isinstance(other, XsdUnion) and any(self.is_derived(mt) for mt in other.member_types) def normalize(self, text: Union[str, bytes]) -> str: """ Normalize and restrict value-space with pre-lexical and lexical facets. :param text: text string encoded value. :return: a normalized string. """ if isinstance(text, bytes): text = text.decode('utf-8') elif not isinstance(text, str): raise XMLSchemaValueError('argument is not a string: %r' % text) if self.white_space == 'replace': return self._REGEX_SPACE.sub(' ', text) elif self.white_space == 'collapse': return self._REGEX_SPACES.sub(' ', text).strip() else: return text def text_decode(self, text: str) -> AtomicValueType: return cast(AtomicValueType, self.decode(text, validation='skip')) def iter_decode(self, obj: Union[str, bytes], validation: str = 'lax', **kwargs: Any) -> IterDecodeType[DecodedValueType]: if obj is None: yield obj else: text = self.normalize(obj) if self.patterns is not None: try: self.patterns(text) except XMLSchemaValidationError as err: yield err for validator in self.validators: try: validator(text) except XMLSchemaValidationError as err: yield err yield text def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[EncodedValueType]: if not isinstance(obj, (str, bytes)): reason = "a {!r} or {!r} object required".format(str, bytes) yield XMLSchemaEncodeError(self, obj, str, reason) else: text = self.normalize(obj) if self.patterns is not None: try: self.patterns(text) except XMLSchemaValidationError as err: yield err for validator in self.validators: try: validator(text) except XMLSchemaValidationError as err: yield err yield text def get_facet(self, tag: str) -> Optional[FacetsValueType]: return self.facets.get(tag) # # simpleType's derived classes: class XsdAtomic(XsdSimpleType): """ Class for atomic simpleType definitions. An atomic definition has a base_type attribute that refers to primitive or derived atomic built-in type or another derived simpleType. """ _special_types = {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE, XSD_ANY_ATOMIC_TYPE} _ADMITTED_TAGS = {XSD_RESTRICTION, XSD_SIMPLE_TYPE} def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent] = None, name: Optional[str] = None, facets: Optional[Dict[Optional[str], FacetsValueType]] = None, base_type: Optional[BaseXsdType] = None) -> None: if base_type is None: self.primitive_type = self else: self.base_type = base_type super(XsdAtomic, self).__init__(elem, schema, parent, name, facets) def __repr__(self) -> str: if self.name is None: return '%s(primitive_type=%r)' % ( self.__class__.__name__, self.primitive_type.local_name ) else: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) def __setattr__(self, name: str, value: Any) -> None: super(XsdAtomic, self).__setattr__(name, value) if name == 'base_type': if not hasattr(self, 'white_space'): try: self.white_space = value.white_space except AttributeError: pass try: if value.is_simple(): self.primitive_type = value.primitive_type else: self.primitive_type = value.content.primitive_type except AttributeError: self.primitive_type = value @property def variety(self) -> Optional[str]: return 'atomic' @property def admitted_facets(self) -> Set[str]: if self.primitive_type.is_complex(): return XSD_10_FACETS if self.xsd_version == '1.0' else XSD_11_FACETS return self.primitive_type.admitted_facets def is_datetime(self) -> bool: return self.primitive_type.to_python.__name__ == 'fromstring' def get_facet(self, tag: str) -> Optional[FacetsValueType]: facet = self.facets.get(tag) if facet is not None: return facet elif self.base_type is not None: return self.base_type.get_facet(tag) else: return None def is_atomic(self) -> bool: return True class XsdAtomicBuiltin(XsdAtomic): """ Class for defining XML Schema built-in simpleType atomic datatypes. An instance contains a Python's type transformation and a list of validator functions. The 'base_type' is not used for validation, but only for reference to the XML Schema restriction hierarchy. Type conversion methods: - to_python(value): Decoding from XML - from_python(value): Encoding to XML """ def __init__(self, elem: ElementType, schema: SchemaType, name: str, python_type: Type[Any], base_type: Optional['XsdAtomicBuiltin'] = None, admitted_facets: Optional[Set[str]] = None, facets: Optional[Dict[Optional[str], FacetsValueType]] = None, to_python: Any = None, from_python: Any = None) -> None: """ :param name: the XSD type's qualified name. :param python_type: the correspondent Python's type. If a tuple of types \ is provided uses the first and consider the others as compatible types. :param base_type: the reference base type, None if it's a primitive type. :param admitted_facets: admitted facets tags for type (required for primitive types). :param facets: optional facets validators. :param to_python: optional decode function. :param from_python: optional encode function. """ if isinstance(python_type, tuple): self.instance_types, python_type = python_type, python_type[0] else: self.instance_types = python_type if not callable(python_type): raise XMLSchemaTypeError("%r object is not callable" % python_type.__class__) if base_type is None and not admitted_facets and name != XSD_ERROR: raise XMLSchemaValueError("argument 'admitted_facets' must be " "a not empty set of a primitive type") self._admitted_facets = admitted_facets super(XsdAtomicBuiltin, self).__init__(elem, schema, None, name, facets, base_type) self.python_type = python_type self.to_python = to_python if to_python is not None else python_type self.from_python = from_python if from_python is not None else str def __repr__(self) -> str: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) @property def admitted_facets(self) -> Set[str]: return self._admitted_facets or self.primitive_type.admitted_facets def iter_decode(self, obj: Union[str, bytes], validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[DecodedValueType]: if isinstance(obj, (str, bytes)): obj = self.normalize(obj) elif obj is not None and not isinstance(obj, self.instance_types): reason = "value is not an instance of {!r}".format(self.instance_types) yield XMLSchemaDecodeError(self, obj, self.to_python, reason) if validation == 'skip': try: yield self.to_python(obj) except (ValueError, DecimalException): yield str(obj) return if self.patterns is not None: try: self.patterns(obj) except XMLSchemaValidationError as err: yield err try: result = self.to_python(obj) except (ValueError, DecimalException) as err: yield XMLSchemaDecodeError(self, obj, self.to_python, reason=str(err)) yield None return except TypeError: # xs:error type (eg. an XSD 1.1 type alternative used to catch invalid values) reason = "invalid value {!r}".format(obj) yield self.validation_error(validation, error=reason, obj=obj) yield None return for validator in self.validators: try: validator(result) except XMLSchemaValidationError as err: yield err if self.name not in {XSD_QNAME, XSD_IDREF, XSD_ID}: pass elif self.name == XSD_QNAME: if ':' in obj: try: prefix, name = obj.split(':') except ValueError: pass else: try: result = '{%s}%s' % (kwargs['namespaces'][prefix], name) except (TypeError, KeyError): try: if kwargs['source'].namespace != XSD_NAMESPACE: reason = "unmapped prefix %r on QName" % prefix yield self.validation_error(validation, error=reason, obj=obj) except KeyError: pass else: try: default_namespace = kwargs['namespaces'][''] except (TypeError, KeyError): pass else: if default_namespace: result = '{%s}%s' % (default_namespace, obj) elif self.name == XSD_IDREF: try: id_map = kwargs['id_map'] except KeyError: pass else: if obj not in id_map: id_map[obj] = 0 elif kwargs.get('level') != 0: try: id_map = kwargs['id_map'] except KeyError: pass else: try: id_list = kwargs['id_list'] except KeyError: if not id_map[obj]: id_map[obj] = 1 else: reason = "duplicated xs:ID value {!r}".format(obj) yield self.validation_error(validation, error=reason, obj=obj) else: if not id_map[obj]: id_map[obj] = 1 id_list.append(obj) if len(id_list) > 1 and self.xsd_version == '1.0': reason = "no more than one attribute of type ID should " \ "be present in an element" yield self.validation_error(validation, reason, obj, **kwargs) elif obj not in id_list or self.xsd_version == '1.0': reason = "duplicated xs:ID value {!r}".format(obj) yield self.validation_error(validation, error=reason, obj=obj) yield result def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[EncodedValueType]: if isinstance(obj, (str, bytes)): obj = self.normalize(obj) if validation == 'skip': try: yield self.from_python(obj) except ValueError: yield str(obj) return elif isinstance(obj, bool): types_: Any = self.instance_types if types_ is not bool or (isinstance(types_, tuple) and bool in types_): reason = "boolean value {!r} requires a {!r} decoder".format(obj, bool) yield XMLSchemaEncodeError(self, obj, self.from_python, reason) obj = self.python_type(obj) elif not isinstance(obj, self.instance_types): reason = "{!r} is not an instance of {!r}".format(obj, self.instance_types) yield XMLSchemaEncodeError(self, obj, self.from_python, reason) try: value = self.python_type(obj) if value != obj and not isinstance(value, str) \ and not isinstance(obj, (str, bytes)): raise ValueError() obj = value except (ValueError, TypeError) as err: yield XMLSchemaEncodeError(self, obj, self.from_python, reason=str(err)) yield None return else: if value == obj or str(value) == str(obj): obj = value else: reason = "Invalid value {!r}".format(obj) yield XMLSchemaEncodeError(self, obj, self.from_python, reason) yield None return for validator in self.validators: try: validator(obj) except XMLSchemaValidationError as err: yield err try: text = self.from_python(obj) except ValueError as err: yield XMLSchemaEncodeError(self, obj, self.from_python, reason=str(err)) yield None else: if self.patterns is not None: try: self.patterns(text) except XMLSchemaValidationError as err: yield err yield text class XsdList(XsdSimpleType): """ Class for 'list' definitions. A list definition has an item_type attribute that refers to an atomic or union simpleType definition. .. <list id = ID itemType = QName {any attributes with non-schema namespace ...}> Content: (annotation?, simpleType?) </list> """ base_type: XsdSimpleType _ADMITTED_TAGS = {XSD_LIST} _white_space_elem = etree_element( XSD_WHITE_SPACE, attrib={'value': 'collapse', 'fixed': 'true'} ) def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent], name: Optional[str] = None) -> None: facets: Optional[Dict[Optional[str], FacetsValueType]] = { XSD_WHITE_SPACE: XsdWhiteSpaceFacet(self._white_space_elem, schema, self, self) } super(XsdList, self).__init__(elem, schema, parent, name, facets) def __repr__(self) -> str: if self.name is None: return '%s(item_type=%r)' % (self.__class__.__name__, self.base_type) else: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) def __setattr__(self, name: str, value: Any) -> None: if name == 'elem' and value is not None and value.tag != XSD_LIST: if value.tag == XSD_SIMPLE_TYPE: for child in value: if child.tag == XSD_LIST: super(XsdList, self).__setattr__(name, child) return raise XMLSchemaValueError("a %r definition required for %r." % (XSD_LIST, self)) elif name == 'base_type': if not value.is_atomic(): raise XMLSchemaValueError("%r: a list must be based on atomic data types." % self) elif name == 'white_space' and value is None: value = 'collapse' super(XsdList, self).__setattr__(name, value) def _parse(self) -> None: base_type: Any child = self._parse_child_component(self.elem) if child is not None: # Case of a local simpleType declaration inside the list tag try: base_type = self.schema.simple_type_factory(child, parent=self) except XMLSchemaParseError as err: self.parse_error(err) base_type = self.any_atomic_type if 'itemType' in self.elem.attrib: self.parse_error("ambiguous list type declaration") else: # List tag with itemType attribute that refers to a global type try: item_qname = self.schema.resolve_qname(self.elem.attrib['itemType']) except (KeyError, ValueError, RuntimeError) as err: if 'itemType' not in self.elem.attrib: self.parse_error("missing list type declaration") else: self.parse_error(err) base_type = self.any_atomic_type else: try: base_type = self.maps.lookup_type(item_qname) except KeyError: self.parse_error("unknown itemType %r" % self.elem.attrib['itemType']) base_type = self.any_atomic_type else: if isinstance(base_type, tuple): self.parse_error( "circular definition found for type {!r}".format(item_qname) ) base_type = self.any_atomic_type if base_type.final == '#all' or 'list' in base_type.final: self.parse_error( "'final' value of the itemType %r forbids derivation by list" % base_type ) if base_type.name == XSD_ANY_ATOMIC_TYPE: self.parse_error("Cannot use xs:anyAtomicType as base type of a user-defined type") try: self.base_type = base_type except XMLSchemaValueError as err: self.parse_error(err) self.base_type = self.any_atomic_type else: if not base_type.allow_empty and self.min_length != 0: self.allow_empty = False @property def variety(self) -> Optional[str]: return 'list' @property def admitted_facets(self) -> Set[str]: return XSD_10_LIST_FACETS if self.xsd_version == '1.0' else XSD_11_LIST_FACETS @property def item_type(self) -> BaseXsdType: return self.base_type def is_atomic(self) -> bool: return False def is_list(self) -> bool: return True def is_derived(self, other: Union[BaseXsdType, Tuple[ElementType, SchemaType]], derivation: Optional[str] = None) -> bool: if self is other: return True elif isinstance(other, tuple): other[1].parse_error(f"global type {other[0].tag!r} is not built") return False elif derivation and self.derivation and derivation != self.derivation: return False elif other.name in self._special_types: return derivation != 'extension' elif self.base_type is other: return True else: return False def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self if self.base_type.parent is not None: yield from self.base_type.iter_components(xsd_classes) def iter_decode(self, obj: Union[str, bytes], # type: ignore[override] validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[List[DecodedValueType]]: items = [] for chunk in self.normalize(obj).split(): for result in self.base_type.iter_decode(chunk, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: items.append(result) else: yield items def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[EncodedValueType]: if not hasattr(obj, '__iter__') or isinstance(obj, (str, bytes)): obj = [obj] encoded_items: List[Any] = [] for item in obj: for result in self.base_type.iter_encode(item, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: encoded_items.append(result) yield ' '.join(item for item in encoded_items if item is not None) class XsdUnion(XsdSimpleType): """ Class for 'union' definitions. A union definition has a member_types attribute that refers to a 'simpleType' definition. .. <union id = ID memberTypes = List of QName {any attributes with non-schema namespace ...}> Content: (annotation?, simpleType*) </union> """ member_types: Any = () _ADMITTED_TYPES: Any = XsdSimpleType _ADMITTED_TAGS = {XSD_UNION} def __init__(self, elem: ElementType, schema: SchemaType, parent: Optional[XsdComponent], name: Optional[str] = None) -> None: super(XsdUnion, self).__init__(elem, schema, parent, name, facets=None) def __repr__(self) -> str: if self.name is None: return '%s(member_types=%r)' % (self.__class__.__name__, self.member_types) else: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) def __setattr__(self, name: str, value: Any) -> None: if name == 'elem' and value is not None and value.tag != XSD_UNION: if value.tag == XSD_SIMPLE_TYPE: for child in value: if child.tag == XSD_UNION: super(XsdUnion, self).__setattr__(name, child) return raise XMLSchemaValueError("a %r definition required for %r." % (XSD_UNION, self)) elif name == 'white_space': if not (value is None or value == 'collapse'): raise XMLSchemaValueError("Wrong value % for attribute 'white_space'." % value) value = 'collapse' super(XsdUnion, self).__setattr__(name, value) def _parse(self) -> None: mt: Any member_types = [] for child in self.elem: if child.tag != XSD_ANNOTATION and not callable(child.tag): mt = self.schema.simple_type_factory(child, parent=self) if isinstance(mt, XMLSchemaParseError): self.parse_error(mt) else: member_types.append(mt) if 'memberTypes' in self.elem.attrib: for name in self.elem.attrib['memberTypes'].split(): try: type_qname = self.schema.resolve_qname(name) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) continue try: mt = self.maps.lookup_type(type_qname) except KeyError: self.parse_error("unknown member type %r" % type_qname) mt = self.any_atomic_type except XMLSchemaParseError as err: self.parse_error(err) mt = self.any_atomic_type if isinstance(mt, tuple): self.parse_error( "circular definition found on xs:union type {!r}".format(self.name) ) continue elif not isinstance(mt, self._ADMITTED_TYPES): self.parse_error("a {!r} required, not {!r}".format(self._ADMITTED_TYPES, mt)) continue elif mt.final == '#all' or 'union' in mt.final: self.parse_error("'final' value of the memberTypes %r " "forbids derivation by union" % member_types) member_types.append(mt) if not member_types: self.parse_error("missing xs:union type declarations") self.member_types = [self.any_atomic_type] elif any(mt.name == XSD_ANY_ATOMIC_TYPE for mt in member_types): self.parse_error("Cannot use xs:anyAtomicType as base type of a user-defined type") else: self.member_types = member_types if all(not mt.allow_empty for mt in member_types): self.allow_empty = False @property def variety(self) -> Optional[str]: return 'union' @property def admitted_facets(self) -> Set[str]: return XSD_10_UNION_FACETS if self.xsd_version == '1.0' else XSD_11_UNION_FACETS def is_atomic(self) -> bool: return all(mt.is_atomic() for mt in self.member_types) def is_list(self) -> bool: return all(mt.is_list() for mt in self.member_types) def is_key(self) -> bool: return any(mt.is_key() for mt in self.member_types) def is_union(self) -> bool: return True def is_dynamic_consistent(self, other: Any) -> bool: return other.name in {XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE} or \ other.is_derived(self) or isinstance(other, self.__class__) and \ any(mt1.is_derived(mt2) for mt1 in other.member_types for mt2 in self.member_types) def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None or isinstance(self, xsd_classes): yield self for mt in filter(lambda x: x.parent is not None, self.member_types): yield from mt.iter_components(xsd_classes) def iter_decode(self, obj: Any, validation: str = 'lax', patterns: Optional[XsdPatternFacets] = None, **kwargs: Any) -> IterDecodeType[DecodedValueType]: # Try decoding the whole text for member_type in self.member_types: for result in member_type.iter_decode(obj, validation='lax', **kwargs): if not isinstance(result, XMLSchemaValidationError): if patterns: obj = member_type.normalize(obj) try: patterns(obj) except XMLSchemaValidationError as err: yield err yield result return break if ' ' not in obj.strip(): reason = "invalid value %r." % obj yield XMLSchemaDecodeError(self, obj, self.member_types, reason) items = [] not_decodable = [] for chunk in obj.split(): for member_type in self.member_types: for result in member_type.iter_decode(chunk, validation='lax', **kwargs): if isinstance(result, XMLSchemaValidationError): break else: items.append(result) else: break else: if validation != 'skip': not_decodable.append(chunk) else: items.append(str(chunk)) if not_decodable: reason = "no type suitable for decoding the values %r." % not_decodable yield XMLSchemaDecodeError(self, obj, self.member_types, reason) yield items if len(items) > 1 else items[0] if items else None def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[EncodedValueType]: for member_type in self.member_types: for result in member_type.iter_encode(obj, validation='lax', **kwargs): if result is not None and not isinstance(result, XMLSchemaValidationError): yield result return elif validation == 'strict': # In 'strict' mode avoid lax encoding by similar types # (eg. float encoded by int) break if hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes)): for member_type in self.member_types: results = [] for item in obj: for result in member_type.iter_encode(item, validation='lax', **kwargs): if result is not None and not isinstance(result, XMLSchemaValidationError): results.append(result) break elif validation == 'strict': break if len(results) == len(obj): yield results break if validation != 'skip': reason = "no type suitable for encoding the object." yield XMLSchemaEncodeError(self, obj, self.member_types, reason) yield None else: yield str(obj) class Xsd11Union(XsdUnion): _ADMITTED_TYPES = XsdAtomic, XsdList, XsdUnion class XsdAtomicRestriction(XsdAtomic): """ Class for XSD 1.0 atomic simpleType and complexType's simpleContent restrictions. .. <restriction base = QName id = ID {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)) </restriction> """ parent: 'XsdSimpleType' base_type: BaseXsdType derivation = 'restriction' _FACETS_BUILDERS = XSD_10_FACETS_BUILDERS _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE} def __setattr__(self, name: str, value: Any) -> None: if name == 'elem' and value is not None: if self.name != XSD_ANY_ATOMIC_TYPE and value.tag != XSD_RESTRICTION: if not (value.tag == XSD_SIMPLE_TYPE and value.get('name') is not None): raise XMLSchemaValueError( "an xs:restriction definition required for %r." % self ) super(XsdAtomicRestriction, self).__setattr__(name, value) def _parse(self) -> None: elem = self.elem if elem.get('name') == XSD_ANY_ATOMIC_TYPE: return # skip special type xs:anyAtomicType elif elem.tag == XSD_SIMPLE_TYPE and elem.get('name') is not None: # Global simpleType with internal restriction elem = cast(ElementType, self._parse_child_component(elem)) if self.name is not None and self.parent is not None: self.parse_error("'name' attribute in a local simpleType definition") base_type: Any = None facets: Any = {} has_attributes = False has_simple_type_child = False if 'base' in elem.attrib: try: base_qname = self.schema.resolve_qname(elem.attrib['base']) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) base_type = self.any_atomic_type else: if base_qname == self.name: if self.redefine is None: self.parse_error("wrong definition with self-reference") base_type = self.any_atomic_type else: base_type = self.base_type else: if self.redefine is not None: self.parse_error("wrong redefinition without self-reference") try: base_type = self.maps.lookup_type(base_qname) except KeyError: self.parse_error("unknown type %r" % elem.attrib['base']) base_type = self.any_atomic_type except XMLSchemaParseError as err: self.parse_error(err) base_type = self.any_atomic_type else: if isinstance(base_type, tuple): msg = "circularity definition between {!r} and {!r}" self.parse_error(msg.format(self, base_qname)) base_type = self.any_atomic_type if base_type.is_simple() and base_type.name == XSD_ANY_SIMPLE_TYPE: self.parse_error("wrong base type {!r}, an atomic type required") elif base_type.is_complex(): if base_type.mixed and base_type.is_emptiable(): child = self._parse_child_component(elem, strict=False) if child is None: self.parse_error("an xs:simpleType definition expected") elif child.tag != XSD_SIMPLE_TYPE: # See: "http://www.w3.org/TR/xmlschema-2/#element-restriction" self.parse_error( "when a complexType with simpleContent restricts a complexType " "with mixed and with emptiable content then a simpleType child " "declaration is required." ) elif self.parent is None or self.parent.is_simple(): self.parse_error( "simpleType restriction of %r is not allowed" % base_type ) for child in elem: if child.tag == XSD_ANNOTATION or callable(child.tag): continue elif child.tag in self._CONTENT_TAIL_TAGS: has_attributes = True # only if it's a complexType restriction elif has_attributes: self.parse_error("unexpected tag after attribute declarations") elif child.tag == XSD_SIMPLE_TYPE: # Case of simpleType declaration inside a restriction if has_simple_type_child: self.parse_error("duplicated simpleType declaration") if base_type is None: try: base_type = self.schema.simple_type_factory(child, parent=self) except XMLSchemaParseError as err: self.parse_error(err, child) base_type = self.any_simple_type elif base_type.is_complex(): if base_type.admit_simple_restriction(): base_type = self.schema.xsd_complex_type_class( elem=elem, schema=self.schema, parent=self, content=self.schema.simple_type_factory(child, parent=self), attributes=base_type.attributes, mixed=base_type.mixed, block=base_type.block, final=base_type.final, ) elif 'base' in elem.attrib: self.parse_error( "restriction with 'base' attribute and simpleType declaration" ) has_simple_type_child = True else: try: facet_class = self._FACETS_BUILDERS[child.tag] except KeyError: self.parse_error("unexpected tag %r in restriction:" % child.tag) continue if child.tag not in facets: facets[child.tag] = facet_class(child, self.schema, self, base_type) elif child.tag not in MULTIPLE_FACETS: self.parse_error("multiple %r constraint facet" % local_name(child.tag)) elif child.tag != XSD_ASSERTION: facets[child.tag].append(child) else: assertion = facet_class(child, self.schema, self, base_type) try: facets[child.tag].append(assertion) except AttributeError: facets[child.tag] = [facets[child.tag], assertion] if base_type is None: self.parse_error("missing base type in restriction:") elif base_type.final == '#all' or 'restriction' in base_type.final: self.parse_error("'final' value of the baseType %r forbids " "derivation by restriction" % base_type) if base_type is self.any_atomic_type: self.parse_error("Cannot use xs:anyAtomicType as base type of a user-defined type") self.base_type = base_type self.facets = facets @property def variety(self) -> Optional[str]: return cast(Optional[str], getattr(self.base_type, 'variety', None)) def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[XsdComponent]: if xsd_classes is None: yield self for facet in self.facets.values(): if isinstance(facet, list): yield from facet # XSD 1.1 assertions can be more than one elif isinstance(facet, XsdFacet): yield facet # only XSD facets, skip callables else: if isinstance(self, xsd_classes): yield self if issubclass(XsdFacet, xsd_classes): for facet in self.facets.values(): if isinstance(facet, list): yield from facet elif isinstance(facet, XsdFacet): yield facet if self.base_type.parent is not None: yield from self.base_type.iter_components(xsd_classes) def iter_decode(self, obj: Union[str, bytes], validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[DecodedValueType]: if isinstance(obj, (str, bytes)): obj = self.normalize(obj) base_type: Any if isinstance(self.base_type, XsdSimpleType): base_type = self.base_type elif self.base_type.has_simple_content(): base_type = self.base_type.content elif self.base_type.mixed: yield obj return else: raise XMLSchemaValueError("wrong base type %r: a simpleType or a complexType with " "simple or mixed content required." % self.base_type) if self.patterns: if not isinstance(self.primitive_type, XsdUnion): try: self.patterns(obj) except XMLSchemaValidationError as err: yield err elif 'patterns' not in kwargs: kwargs['patterns'] = self.patterns for result in base_type.iter_decode(obj, validation, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result if isinstance(result, XMLSchemaDecodeError): yield str(obj) if validation == 'skip' else None else: if result is not None: for validator in self.validators: try: validator(result) except XMLSchemaValidationError as err: yield err yield result return def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[EncodedValueType]: base_type: Any if self.is_list(): if not hasattr(obj, '__iter__') or isinstance(obj, (str, bytes)): obj = [] if obj is None or obj == '' else [obj] base_type = self.base_type else: if isinstance(obj, (str, bytes)): obj = self.normalize(obj) if isinstance(self.base_type, XsdSimpleType): base_type = self.base_type elif self.base_type.has_simple_content(): base_type = self.base_type.content elif self.base_type.mixed: yield str(obj) return else: raise XMLSchemaValueError("wrong base type %r: a simpleType or a complexType with " "simple or mixed content required." % self.base_type) result: Any for result in base_type.iter_encode(obj, validation): if isinstance(result, XMLSchemaValidationError): yield result if isinstance(result, XMLSchemaEncodeError): yield str(obj) if validation == 'skip' else None return else: if self.validators and obj is not None: if isinstance(obj, (str, bytes)) and \ self.primitive_type.to_python is not str and \ isinstance(obj, self.primitive_type.instance_types): try: obj = self.primitive_type.to_python(obj) except (ValueError, DecimalException, TypeError): pass for validator in self.validators: try: validator(obj) except XMLSchemaValidationError as err: yield err if self.patterns: if not isinstance(self.primitive_type, XsdUnion): try: self.patterns(result) except XMLSchemaValidationError as err: yield err elif 'patterns' not in kwargs: kwargs['patterns'] = self.patterns yield result return def is_list(self) -> bool: return self.primitive_type.is_list() def is_union(self) -> bool: return self.primitive_type.is_union() class Xsd11AtomicRestriction(XsdAtomicRestriction): """ Class for XSD 1.1 atomic simpleType and complexType's simpleContent restrictions. .. <restriction base = QName id = ID {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern | assertion | explicitTimezone | {any with namespace: ##other})*)) </restriction> """ _FACETS_BUILDERS = XSD_11_FACETS_BUILDERS _CONTENT_TAIL_TAGS = {XSD_ATTRIBUTE, XSD_ATTRIBUTE_GROUP, XSD_ANY_ATTRIBUTE, XSD_ASSERT} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/wildcards.py��������������������������������������������������0000664�0000000�0000000�00000110363�14211403446�0022234�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains classes for XML Schema wildcards. """ from typing import cast, Any, Callable, Dict, Iterable, Iterator, List, Optional, \ Tuple, Union, Counter from ..exceptions import XMLSchemaValueError from ..names import XSI_NAMESPACE, XSD_ANY, XSD_ANY_ATTRIBUTE, \ XSD_OPEN_CONTENT, XSD_DEFAULT_OPEN_CONTENT, XSI_TYPE from ..aliases import ElementType, SchemaType, SchemaElementType, SchemaAttributeType, \ ModelGroupType, ModelParticleType, AtomicValueType, IterDecodeType, IterEncodeType, \ DecodedValueType, EncodedValueType from ..helpers import get_namespace, raw_xml_encode from ..xpath import XMLSchemaProtocol, ElementProtocol, XMLSchemaProxy, ElementPathMixin from .xsdbase import ValidationMixin, XsdComponent from .particles import ParticleMixin from . import elements OccursCounterType = Counter[Union[ModelParticleType, Tuple[ModelParticleType]]] class XsdWildcard(XsdComponent): names = () namespace: Union[Tuple[str], List[str]] = ('##any',) not_namespace: Union[Tuple[()], List[str]] = () not_qname: Union[Tuple[()], List[str]] = () process_contents = 'strict' # For compatibility with protocol of XSD elements/attributes type = None default = None fixed = None def __repr__(self) -> str: if self.not_namespace: return '%s(not_namespace=%r, process_contents=%r)' % ( self.__class__.__name__, self.not_namespace, self.process_contents ) else: return '%s(namespace=%r, process_contents=%r)' % ( self.__class__.__name__, self.namespace, self.process_contents ) def _parse(self) -> None: # Parse namespace and processContents namespace = self.elem.attrib.get('namespace', '##any').strip() if namespace == '##any': pass elif not namespace: self.namespace = [] # an empty value means no namespace allowed! elif namespace == '##other': self.namespace = [namespace] elif namespace == '##local': self.namespace = [''] elif namespace == '##targetNamespace': self.namespace = [self.target_namespace] else: self.namespace = [] for ns in namespace.split(): if ns == '##local': self.namespace.append('') elif ns == '##targetNamespace': self.namespace.append(self.target_namespace) elif ns.startswith('##'): self.parse_error("wrong value %r in 'namespace' attribute" % ns) else: self.namespace.append(ns) process_contents = self.elem.attrib.get('processContents', 'strict') if process_contents == 'strict': pass elif process_contents not in ('lax', 'skip'): self.parse_error("wrong value %r for 'processContents' " "attribute" % self.process_contents) else: self.process_contents = process_contents def _parse_not_constraints(self) -> None: if 'notNamespace' not in self.elem.attrib: pass elif 'namespace' in self.elem.attrib: self.parse_error("'namespace' and 'notNamespace' attributes are mutually exclusive") else: self.namespace = [] self.not_namespace = [] for ns in self.elem.attrib['notNamespace'].strip().split(): if ns == '##local': self.not_namespace.append('') elif ns == '##targetNamespace': self.not_namespace.append(self.target_namespace) elif ns.startswith('##'): self.parse_error("wrong value %r in 'notNamespace' attribute" % ns) else: self.not_namespace.append(ns) # Parse notQName attribute if 'notQName' not in self.elem.attrib: return not_qname = self.elem.attrib['notQName'].strip().split() if isinstance(self, XsdAnyAttribute) and \ not all(not s.startswith('##') or s == '##defined' for s in not_qname) or \ not all(not s.startswith('##') or s in {'##defined', '##definedSibling'} for s in not_qname): self.parse_error("wrong value for 'notQName' attribute") return try: names = [x if x.startswith('##') else self.schema.resolve_qname(x, False) for x in not_qname] except KeyError as err: self.parse_error("unmapped QName in 'notQName' attribute: %s" % str(err)) return except ValueError as err: self.parse_error("wrong QName format in 'notQName' attribute: %s" % str(err)) return if self.not_namespace: if any(not x.startswith('##') for x in names) and \ all(get_namespace(x) in self.not_namespace for x in names if not x.startswith('##')): self.parse_error("the namespace of each QName in notQName " "is allowed by notNamespace") elif any(not self.is_namespace_allowed(get_namespace(x)) for x in names if not x.startswith('##')): self.parse_error("names in notQName must be in namespaces that are allowed") self.not_qname = names @property def built(self) -> bool: return True def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None, **kwargs: Any) -> bool: if name is None: return False elif not name or name[0] == '{': return self.is_namespace_allowed(get_namespace(name)) elif not default_namespace: return self.is_namespace_allowed('') else: return self.is_namespace_allowed('') or \ self.is_namespace_allowed(default_namespace) def is_namespace_allowed(self, namespace: str) -> bool: if self.not_namespace: return namespace not in self.not_namespace elif '##any' in self.namespace or namespace == XSI_NAMESPACE: return True elif '##other' in self.namespace: if not namespace: return False return namespace != self.target_namespace else: return namespace in self.namespace def deny_namespaces(self, namespaces: List[str]) -> bool: if self.not_namespace: return all(x in self.not_namespace for x in namespaces) elif '##any' in self.namespace: return False elif '##other' in self.namespace: return all(x == self.target_namespace for x in namespaces) else: return all(x not in self.namespace for x in namespaces) def deny_qnames(self, names: Iterable[str]) -> bool: if self.not_namespace: return all(x in self.not_qname or get_namespace(x) in self.not_namespace for x in names) elif '##any' in self.namespace: return all(x in self.not_qname for x in names) elif '##other' in self.namespace: return all(x in self.not_qname or get_namespace(x) == self.target_namespace for x in names) else: return all(x in self.not_qname or get_namespace(x) not in self.namespace for x in names) def is_restriction(self, other: Union[ModelParticleType, 'XsdAnyAttribute'], check_occurs: bool = True) -> bool: if check_occurs and isinstance(self, ParticleMixin) \ and not isinstance(other, XsdAnyAttribute) \ and not self.has_occurs_restriction(other): return False elif not isinstance(other, self.__class__): return False other: XsdWildcard # type: ignore[no-redef] if other.process_contents == 'strict' and self.process_contents != 'strict': return False elif other.process_contents == 'lax' and self.process_contents == 'skip': return False if not self.not_qname and not other.not_qname: pass elif '##defined' in other.not_qname and '##defined' not in self.not_qname: return False elif '##definedSibling' in other.not_qname and '##definedSibling' not in self.not_qname: return False elif other.not_qname: if not self.deny_qnames(x for x in other.not_qname if not x.startswith('##')): return False elif any(not other.is_namespace_allowed(get_namespace(x)) for x in self.not_qname if not x.startswith('##')): return False if self.not_namespace: if other.not_namespace: return all(ns in self.not_namespace for ns in other.not_namespace) elif '##any' in other.namespace: return True elif '##other' in other.namespace: return '' in self.not_namespace and other.target_namespace in self.not_namespace else: return False elif other.not_namespace: if '##any' in self.namespace: return False elif '##other' in self.namespace: return set(other.not_namespace).issubset({'', other.target_namespace}) else: return all(ns not in other.not_namespace for ns in self.namespace) if self.namespace == other.namespace: return True elif '##any' in other.namespace: return True elif '##any' in self.namespace or '##other' in self.namespace: return False elif '##other' in other.namespace: return other.target_namespace not in self.namespace and '' not in self.namespace else: return all(ns in other.namespace for ns in self.namespace) def union(self, other: Union['XsdAnyElement', 'XsdAnyAttribute']) -> None: """ Update an XSD wildcard with the union of itself and another XSD wildcard. """ if not self.not_qname: self.not_qname = other.not_qname[:] else: self.not_qname = [ x for x in self.not_qname if x in other.not_qname or not other.is_namespace_allowed(get_namespace(x)) ] if self.not_namespace: if other.not_namespace: self.not_namespace = [ns for ns in self.not_namespace if ns in other.not_namespace] elif '##any' in other.namespace: self.not_namespace = [] self.namespace = ['##any'] return elif '##other' in other.namespace: not_namespace = ('', other.target_namespace) self.not_namespace = [ns for ns in self.not_namespace if ns in not_namespace] else: self.not_namespace = [ns for ns in self.not_namespace if ns not in other.namespace] if not self.not_namespace: self.namespace = ['##any'] return elif other.not_namespace: if '##any' in self.namespace: return elif '##other' in self.namespace: not_namespace = ('', self.target_namespace) self.not_namespace = [ns for ns in other.not_namespace if ns in not_namespace] else: self.not_namespace = [ns for ns in other.not_namespace if ns not in self.namespace] self.namespace = ['##any'] if not self.not_namespace else [] return w1: XsdWildcard w2: XsdWildcard if '##any' in self.namespace or self.namespace == other.namespace: return elif '##any' in other.namespace: self.namespace = ['##any'] return elif '##other' in other.namespace: w1, w2 = other, self elif '##other' in self.namespace: w1, w2 = self, other else: assert isinstance(self.namespace, list) self.namespace.extend(ns for ns in other.namespace if ns not in self.namespace) return if w1.target_namespace in w2.namespace and '' in w2.namespace: self.namespace = ['##any'] elif '' not in w2.namespace and w1.target_namespace == w2.target_namespace: self.namespace = ['##other'] elif self.xsd_version == '1.0': msg = "not expressible wildcard namespace union: {!r} V {!r}:" raise XMLSchemaValueError(msg.format(other.namespace, self.namespace)) else: self.namespace = [] self.not_namespace = ['', w1.target_namespace] if w1.target_namespace else [''] def intersection(self, other: Union['XsdAnyElement', 'XsdAnyAttribute']) -> None: """ Update an XSD wildcard with the intersection of itself and another XSD wildcard. """ if self.not_qname: self.not_qname.extend(x for x in other.not_qname if x not in self.not_qname) else: self.not_qname = [x for x in other.not_qname] if self.not_namespace: if other.not_namespace: self.not_namespace.extend(ns for ns in other.not_namespace if ns not in self.not_namespace) elif '##any' in other.namespace: pass elif '##other' not in other.namespace: self.namespace = [ns for ns in other.namespace if ns not in self.not_namespace] self.not_namespace = [] else: if other.target_namespace not in self.not_namespace: self.not_namespace.append(other.target_namespace) if '' not in self.not_namespace: self.not_namespace.append('') return elif other.not_namespace: if '##any' in self.namespace: self.not_namespace = [ns for ns in other.not_namespace] self.namespace = [] elif '##other' not in self.namespace: self.namespace = [ns for ns in self.namespace if ns not in other.not_namespace] else: self.not_namespace = [ns for ns in other.not_namespace] if self.target_namespace not in self.not_namespace: self.not_namespace.append(self.target_namespace) if '' not in self.not_namespace: self.not_namespace.append('') self.namespace = [] return if self.namespace == other.namespace: return elif '##any' in other.namespace: return elif '##any' in self.namespace: self.namespace = other.namespace[:] elif '##other' in self.namespace: self.namespace = [ns for ns in other.namespace if ns not in ('', self.target_namespace)] elif '##other' not in other.namespace: self.namespace = [ns for ns in self.namespace if ns in other.namespace] else: assert isinstance(self.namespace, list) if other.target_namespace in self.namespace: self.namespace.remove(other.target_namespace) if '' in self.namespace: self.namespace.remove('') class XsdAnyElement(XsdWildcard, ParticleMixin, ElementPathMixin[SchemaElementType], ValidationMixin[ElementType, Any]): """ Class for XSD 1.0 *any* wildcards. .. <any id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace|##local)) ) : ##any processContents = (lax | skip | strict) : strict {any attributes with non-schema namespace . . .}> Content: (annotation?) </any> """ _ADMITTED_TAGS = {XSD_ANY} precedences: Dict[ModelGroupType, List[ModelParticleType]] copy: Callable[['XsdAnyElement'], 'XsdAnyElement'] def __init__(self, elem: ElementType, schema: SchemaType, parent: XsdComponent) -> None: self.precedences = {} super(XsdAnyElement, self).__init__(elem, schema, parent) def __repr__(self) -> str: if self.namespace: return '%s(namespace=%r, process_contents=%r, occurs=%r)' % ( self.__class__.__name__, self.namespace, self.process_contents, list(self.occurs) ) else: return '%s(not_namespace=%r, process_contents=%r, occurs=%r)' % ( self.__class__.__name__, self.not_namespace, self.process_contents, list(self.occurs) ) @property def xpath_proxy(self) -> XMLSchemaProxy: return XMLSchemaProxy( schema=cast(XMLSchemaProtocol, self.schema), base_element=cast(ElementProtocol, self) ) def _parse(self) -> None: super(XsdAnyElement, self)._parse() self._parse_particle(self.elem) def match(self, name: Optional[str], default_namespace: Optional[str] = None, resolve: bool = False, **kwargs: Any) -> Optional[SchemaElementType]: """ Returns the element wildcard if name is matching the name provided as argument, `None` otherwise. :param name: a local or fully-qualified name. :param default_namespace: used when it's not `None` and not empty for \ completing local name arguments. :param resolve: when `True` it doesn't return the wildcard but try to \ resolve and return the element matching the name. :param kwargs: additional options used by XSD 1.1 xs:any wildcards. """ if not name or not self.is_matching(name, default_namespace, **kwargs): return None elif not resolve: return self try: if name[0] != '{' and default_namespace: return self.maps.lookup_element('{%s}%s' % (default_namespace, name)) else: return self.maps.lookup_element(name) except LookupError: return None def __iter__(self) -> Iterator[Any]: return iter(()) def iter(self, tag: Optional[str] = None) -> Iterator[Any]: return iter(()) def iterchildren(self, tag: Optional[str] = None) -> Iterator[Any]: return iter(()) @staticmethod def iter_substitutes() -> Iterator[Any]: return iter(()) def iter_decode(self, obj: ElementType, validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[Any]: if not self.is_matching(obj.tag): reason = "{!r} is not allowed here".format(obj) yield self.validation_error(validation, reason, obj, **kwargs) if self.process_contents == 'skip': if 'process_skipped' not in kwargs or not kwargs['process_skipped']: return namespace = get_namespace(obj.tag) if not self.maps.load_namespace(namespace): reason = f"unavailable namespace {namespace!r}" else: try: xsd_element = self.maps.lookup_element(obj.tag) except LookupError: reason = f"element {obj.tag!r} not found" else: yield from xsd_element.iter_decode(obj, validation, **kwargs) return if XSI_TYPE in obj.attrib: if self.process_contents == 'strict': xsd_element = self.maps.validator.create_element( obj.tag, parent=self, form='unqualified' ) else: xsd_element = self.maps.validator.create_element( obj.tag, parent=self, nillable='true', form='unqualified' ) yield from xsd_element.iter_decode(obj, validation, **kwargs) return if validation != 'skip' and self.process_contents == 'strict': yield self.validation_error(validation, reason, obj, **kwargs) yield from self.any_type.iter_decode(obj, validation, **kwargs) def iter_encode(self, obj: Tuple[str, ElementType], validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[Any]: name, value = obj namespace = get_namespace(name) if not self.is_namespace_allowed(namespace): reason = "element {!r} is not allowed here".format(name) yield self.validation_error(validation, reason, value, **kwargs) if self.process_contents == 'skip': if 'process_skipped' not in kwargs or not kwargs['process_skipped']: return if not self.maps.load_namespace(namespace): reason = f"unavailable namespace {namespace!r}" else: try: xsd_element = self.maps.lookup_element(name) except LookupError: reason = f"element {name!r} not found" else: yield from xsd_element.iter_encode(value, validation, **kwargs) return # Check if there is an xsi:type attribute, but it has to extract # attributes using the converter instance. if self.process_contents == 'strict': xsd_element = self.maps.validator.create_element( name, parent=self, form='unqualified' ) else: xsd_element = self.maps.validator.create_element( name, parent=self, nillable='true', form='unqualified' ) try: converter = kwargs['converter'] except KeyError: converter = kwargs['converter'] = self.schema.get_converter(**kwargs) try: level = kwargs['level'] except KeyError: element_data = converter.element_encode(value, xsd_element) else: element_data = converter.element_encode(value, xsd_element, level) if XSI_TYPE in element_data.attributes: yield from xsd_element.iter_encode(value, validation, **kwargs) return if validation != 'skip' and self.process_contents == 'strict': yield self.validation_error(validation, reason, **kwargs) yield from self.any_type.iter_encode(obj, validation, **kwargs) def is_overlap(self, other: ModelParticleType) -> bool: if not isinstance(other, XsdAnyElement): if isinstance(other, elements.XsdElement): return other.is_overlap(self) return False if self.not_namespace: if other.not_namespace: return True elif '##any' in other.namespace: return True elif '##other' in other.namespace: return True else: return any(ns not in self.not_namespace for ns in other.namespace) elif other.not_namespace: if '##any' in self.namespace: return True elif '##other' in self.namespace: return True else: return any(ns not in other.not_namespace for ns in self.namespace) elif self.namespace == other.namespace: return True elif '##any' in self.namespace or '##any' in other.namespace: return True elif '##other' in self.namespace: return any(ns and ns != self.target_namespace for ns in other.namespace) elif '##other' in other.namespace: return any(ns and ns != other.target_namespace for ns in self.namespace) else: return any(ns in self.namespace for ns in other.namespace) def is_consistent(self, other: SchemaElementType, **kwargs: Any) -> bool: return True class XsdAnyAttribute(XsdWildcard, ValidationMixin[Tuple[str, str], DecodedValueType]): """ Class for XSD 1.0 *anyAttribute* wildcards. .. <anyAttribute id = ID namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) processContents = (lax | skip | strict) : strict {any attributes with non-schema namespace . . .}> Content: (annotation?) </anyAttribute> """ copy: Callable[['XsdAnyAttribute'], 'XsdAnyAttribute'] _ADMITTED_TAGS = {XSD_ANY_ATTRIBUTE} # Added for compatibility with protocol of XSD attributes use = None inheritable = False # XSD 1.1 attributes def match(self, name: Optional[str], default_namespace: Optional[str] = None, resolve: bool = False, **kwargs: Any) -> Optional[SchemaAttributeType]: """ Returns the attribute wildcard if name is matching the name provided as argument, `None` otherwise. :param name: a local or fully-qualified name. :param default_namespace: used when it's not `None` and not empty for \ completing local name arguments. :param resolve: when `True` it doesn't return the wildcard but try to \ resolve and return the attribute matching the name. :param kwargs: additional options that can be used by certain components. """ if not name or not self.is_matching(name, default_namespace, **kwargs): return None elif not resolve: return self try: if name[0] != '{' and default_namespace: return self.maps.lookup_attribute('{%s}%s' % (default_namespace, name)) else: return self.maps.lookup_attribute(name) except LookupError: return None def iter_decode(self, obj: Tuple[str, str], validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[DecodedValueType]: name, value = obj if not self.is_matching(name): reason = "attribute %r not allowed." % name yield self.validation_error(validation, reason, obj, **kwargs) if self.process_contents == 'skip': if 'process_skipped' not in kwargs or not kwargs['process_skipped']: return if self.maps.load_namespace(get_namespace(name)): try: xsd_attribute = self.maps.lookup_attribute(name) except LookupError: if validation != 'skip' and self.process_contents == 'strict': reason = "attribute %r not found." % name yield self.validation_error(validation, reason, obj, **kwargs) else: yield from xsd_attribute.iter_decode(value, validation, **kwargs) return elif validation != 'skip' and self.process_contents == 'strict': reason = "unavailable namespace {!r}".format(get_namespace(name)) yield self.validation_error(validation, reason, **kwargs) yield value def iter_encode(self, obj: Tuple[str, AtomicValueType], validation: str = 'lax', **kwargs: Any) -> IterEncodeType[EncodedValueType]: name, value = obj namespace = get_namespace(name) if not self.is_namespace_allowed(namespace): reason = "attribute %r not allowed." % name yield self.validation_error(validation, reason, obj, **kwargs) if self.process_contents == 'skip': if 'process_skipped' not in kwargs or not kwargs['process_skipped']: return if self.maps.load_namespace(namespace): try: xsd_attribute = self.maps.lookup_attribute(name) except LookupError: if validation != 'skip' and self.process_contents == 'strict': reason = "attribute %r not found." % name yield self.validation_error(validation, reason, obj, **kwargs) else: yield from xsd_attribute.iter_encode(value, validation, **kwargs) return elif validation != 'skip' and self.process_contents == 'strict': reason = "unavailable namespace {!r}".format(get_namespace(name)) yield self.validation_error(validation, reason, **kwargs) yield raw_xml_encode(value) class Xsd11AnyElement(XsdAnyElement): """ Class for XSD 1.1 *any* declarations. .. <any id = ID maxOccurs = (nonNegativeInteger | unbounded) : 1 minOccurs = nonNegativeInteger : 1 namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) notNamespace = List of (anyURI | (##targetNamespace | ##local)) notQName = List of (QName | (##defined | ##definedSibling)) processContents = (lax | skip | strict) : strict {any attributes with non-schema namespace . . .}> Content: (annotation?) </any> """ def _parse(self) -> None: super(Xsd11AnyElement, self)._parse() self._parse_not_constraints() def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None, group: Optional[ModelGroupType] = None, occurs: Optional[OccursCounterType] = None, **kwargs: Any) -> bool: """ Returns `True` if the component name is matching the name provided as argument, `False` otherwise. For XSD elements the matching is extended to substitutes. :param name: a local or fully-qualified name. :param default_namespace: used if it's not None and not empty for completing \ the name argument in case it's a local name. :param group: used only by XSD 1.1 any element wildcards to verify siblings in \ case of ##definedSibling value in notQName attribute. :param occurs: a Counter instance for verify model occurrences counting. """ if name is None: return False elif not name or name[0] == '{': if not self.is_namespace_allowed(get_namespace(name)): return False elif not default_namespace: if not self.is_namespace_allowed(''): return False else: name = '{%s}%s' % (default_namespace, name) if not self.is_namespace_allowed('') \ and not self.is_namespace_allowed(default_namespace): return False if group in self.precedences: if occurs is None: if any(e.is_matching(name) for e in self.precedences[group]): return False elif any(e.is_matching(name) and not e.is_over(occurs[e]) for e in self.precedences[group]): return False if '##defined' in self.not_qname and name in self.maps.elements: return False if group and '##definedSibling' in self.not_qname: if any(e.is_matching(name) for e in group.iter_elements() if not isinstance(e, XsdAnyElement)): return False return name not in self.not_qname def is_consistent(self, other: SchemaElementType, **kwargs: Any) -> bool: if isinstance(other, XsdAnyElement) or self.process_contents == 'skip': return True xsd_element = self.match(other.name, other.default_namespace, resolve=True) return xsd_element is None or other.is_consistent(xsd_element, strict=False) def add_precedence(self, other: ModelParticleType, group: ModelGroupType) -> None: try: self.precedences[group].append(other) except KeyError: self.precedences[group] = [other] class Xsd11AnyAttribute(XsdAnyAttribute): """ Class for XSD 1.1 *anyAttribute* declarations. .. <anyAttribute id = ID namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) notNamespace = List of (anyURI | (##targetNamespace | ##local)) notQName = List of (QName | ##defined) processContents = (lax | skip | strict) : strict {any attributes with non-schema namespace . . .}> Content: (annotation?) </anyAttribute> """ def _parse(self) -> None: super(Xsd11AnyAttribute, self)._parse() self._parse_not_constraints() def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None, **kwargs: Any) -> bool: if name is None: return False elif not name or name[0] == '{': namespace = get_namespace(name) elif not default_namespace: namespace = '' else: name = '{%s}%s' % (default_namespace, name) namespace = default_namespace if '##defined' in self.not_qname and name in self.maps.attributes: xsd_attribute = self.maps.attributes[name] if isinstance(xsd_attribute, tuple): if xsd_attribute[1] is self.schema: return False elif xsd_attribute.schema is self.schema: return False return name not in self.not_qname and self.is_namespace_allowed(namespace) class XsdOpenContent(XsdComponent): """ Class for XSD 1.1 *openContent* model definitions. .. <openContent id = ID mode = (none | interleave | suffix) : interleave {any attributes with non-schema namespace . . .}> Content: (annotation?), (any?) </openContent> """ _ADMITTED_TAGS = {XSD_OPEN_CONTENT} mode = 'interleave' any_element = None # type: Xsd11AnyElement def __init__(self, elem: ElementType, schema: SchemaType, parent: XsdComponent) -> None: super(XsdOpenContent, self).__init__(elem, schema, parent) def __repr__(self) -> str: return '%s(mode=%r)' % (self.__class__.__name__, self.mode) def _parse(self) -> None: super(XsdOpenContent, self)._parse() try: self.mode = self.elem.attrib['mode'] except KeyError: pass else: if self.mode not in {'none', 'interleave', 'suffix'}: self.parse_error("wrong value %r for 'mode' attribute." % self.mode) child = self._parse_child_component(self.elem) if self.mode == 'none': if child is not None and child.tag == XSD_ANY: self.parse_error("an openContent with mode='none' must not " "have an <xs:any> child declaration") elif child is None or child.tag != XSD_ANY: self.parse_error("an <xs:any> child declaration is required") else: any_element = Xsd11AnyElement(child, self.schema, self) any_element.min_occurs = 0 any_element.max_occurs = None self.any_element = any_element @property def built(self) -> bool: return True def is_restriction(self, other: 'XsdOpenContent') -> bool: if other is None or other.mode == 'none': return self.mode == 'none' elif self.mode == 'interleave' and other.mode == 'suffix': return False else: return self.any_element.is_restriction(other.any_element) class XsdDefaultOpenContent(XsdOpenContent): """ Class for XSD 1.1 *defaultOpenContent* model definitions. .. <defaultOpenContent appliesToEmpty = boolean : false id = ID mode = (interleave | suffix) : interleave {any attributes with non-schema namespace . . .}> Content: (annotation?, any) </defaultOpenContent> """ _ADMITTED_TAGS = {XSD_DEFAULT_OPEN_CONTENT} applies_to_empty = False def __init__(self, elem: ElementType, schema: SchemaType) -> None: super(XsdOpenContent, self).__init__(elem, schema) def _parse(self) -> None: super(XsdDefaultOpenContent, self)._parse() if self.parent is not None: self.parse_error("defaultOpenContent must be a child of the schema") if self.mode == 'none': self.parse_error("the attribute 'mode' of a defaultOpenContent cannot be 'none'") if self._parse_child_component(self.elem) is None: self.parse_error("a defaultOpenContent declaration cannot be empty") if 'appliesToEmpty' in self.elem.attrib: if self.elem.attrib['appliesToEmpty'].strip() in {'true', '1'}: self.applies_to_empty = True �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/validators/xsdbase.py����������������������������������������������������0000664�0000000�0000000�00000117604�14211403446�0021716�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module contains base functions and classes XML Schema components. """ import re from typing import TYPE_CHECKING, cast, Any, Dict, Generic, List, Iterator, Optional, \ Set, Tuple, TypeVar, Union, MutableMapping import elementpath from ..exceptions import XMLSchemaValueError, XMLSchemaTypeError from ..names import XSD_ANNOTATION, XSD_APPINFO, XSD_DOCUMENTATION, \ XSD_ANY_TYPE, XSD_ANY_SIMPLE_TYPE, XSD_ANY_ATOMIC_TYPE, XSD_ID, \ XSD_QNAME, XSD_OVERRIDE, XSD_NOTATION_TYPE, XSD_DECIMAL from ..etree import is_etree_element, etree_tostring, etree_element from ..aliases import ElementType, NamespacesType, SchemaType, BaseXsdType, \ ComponentClassType, ExtraValidatorType, DecodeType, IterDecodeType, \ EncodeType, IterEncodeType from ..helpers import get_qname, local_name, get_prefixed_qname from ..resources import XMLResource from .exceptions import XMLSchemaParseError, XMLSchemaValidationError if TYPE_CHECKING: from .simple_types import XsdSimpleType from .complex_types import XsdComplexType from .elements import XsdElement from .groups import XsdGroup from .global_maps import XsdGlobals XSD_TYPE_DERIVATIONS = {'extension', 'restriction'} XSD_ELEMENT_DERIVATIONS = {'extension', 'restriction', 'substitution'} XSD_VALIDATION_MODES = {'strict', 'lax', 'skip'} """ XML Schema validation modes Ref.: https://www.w3.org/TR/xmlschema11-1/#key-va """ def check_validation_mode(validation: str) -> None: if validation not in XSD_VALIDATION_MODES: raise XMLSchemaValueError("validation mode can be 'strict', " "'lax' or 'skip': %r" % validation) class XsdValidator: """ Common base class for XML Schema validator, that represents a PSVI (Post Schema Validation Infoset) information item. A concrete XSD validator have to report its validity collecting building errors and implementing the properties. :param validation: defines the XSD validation mode to use for build the validator, \ its value can be 'strict', 'lax' or 'skip'. Strict mode is the default. :type validation: str :ivar validation: XSD validation mode. :vartype validation: str :ivar errors: XSD validator building errors. :vartype errors: list """ elem: Optional[etree_element] = None namespaces: Any = None errors: List[XMLSchemaParseError] def __init__(self, validation: str = 'strict') -> None: self.validation = validation self.errors = [] @property def built(self) -> bool: """ Property that is ``True`` if XSD validator has been fully parsed and built, ``False`` otherwise. For schemas the property is checked on all global components. For XSD components check only the building of local subcomponents. """ raise NotImplementedError() @property def validation_attempted(self) -> str: """ Property that returns the *validation status* of the XSD validator. It can be 'full', 'partial' or 'none'. | https://www.w3.org/TR/xmlschema-1/#e-validation_attempted | https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#e-validation_attempted """ raise NotImplementedError() @property def validity(self) -> str: """ Property that returns the XSD validator's validity. It can be ‘valid’, ‘invalid’ or ‘notKnown’. | https://www.w3.org/TR/xmlschema-1/#e-validity | https://www.w3.org/TR/2012/REC-xmlschema11-1-20120405/#e-validity """ if self.validation == 'skip': return 'notKnown' elif self.errors or any(comp.errors for comp in self.iter_components()): return 'invalid' elif self.built: return 'valid' else: return 'notKnown' def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator[Union['XsdComponent', SchemaType, 'XsdGlobals']]: """ Creates an iterator for traversing all XSD components of the validator. :param xsd_classes: returns only a specific class/classes of components, \ otherwise returns all components. """ raise NotImplementedError() @property def all_errors(self) -> List[XMLSchemaParseError]: """ A list with all the building errors of the XSD validator and its components. """ errors = [] for comp in self.iter_components(): if comp.errors: errors.extend(comp.errors) return errors def copy(self) -> 'XsdValidator': validator: 'XsdValidator' = object.__new__(self.__class__) validator.__dict__.update(self.__dict__) validator.errors = self.errors[:] # shallow copy duplicates errors list return validator __copy__ = copy def parse_error(self, error: Union[str, Exception], elem: Optional[ElementType] = None, validation: Optional[str] = None) -> None: """ Helper method for registering parse errors. Does nothing if validation mode is 'skip'. Il validation mode is 'lax' collects the error, otherwise raise the error. :param error: can be a parse error or an error message. :param elem: the Element instance related to the error, for default uses the 'elem' \ attribute of the validator, if it's present. :param validation: overrides the default validation mode of the validator. """ if validation is not None: check_validation_mode(validation) else: validation = self.validation if validation == 'skip': return elif elem is None: elem = self.elem elif not is_etree_element(elem): msg = "the argument 'elem' must be an Element instance, not {!r}." raise XMLSchemaTypeError(msg.format(elem)) if isinstance(error, XMLSchemaParseError): error.validator = self error.namespaces = getattr(self, 'namespaces', None) error.elem = elem error.source = getattr(self, 'source', None) elif isinstance(error, Exception): message = str(error).strip() if message[0] in '\'"' and message[0] == message[-1]: message = message.strip('\'"') error = XMLSchemaParseError(self, message, elem) elif isinstance(error, str): error = XMLSchemaParseError(self, error, elem) else: msg = "'error' argument must be an exception or a string, not {!r}." raise XMLSchemaTypeError(msg.format(error)) if validation == 'lax': self.errors.append(error) else: raise error def validation_error(self, validation: str, error: Union[str, Exception], obj: Any = None, source: Optional[XMLResource] = None, namespaces: Optional[NamespacesType] = None, **_kwargs: Any) -> XMLSchemaValidationError: """ Helper method for generating and updating validation errors. If validation mode is 'lax' or 'skip' returns the error, otherwise raises the error. :param validation: an error-compatible validation mode: can be 'lax' or 'strict'. :param error: an error instance or the detailed reason of failed validation. :param obj: the instance related to the error. :param source: the XML resource related to the validation process. :param namespaces: is an optional mapping from namespace prefix to URI. :param _kwargs: keyword arguments of the validation process that are not used. """ check_validation_mode(validation) if isinstance(error, XMLSchemaValidationError): if error.namespaces is None and namespaces is not None: error.namespaces = namespaces if error.source is None and source is not None: error.source = source if error.obj is None and obj is not None: error.obj = obj if error.elem is None and obj is not None and is_etree_element(obj): error.elem = obj if is_etree_element(error.obj) and obj.tag == error.obj.tag: error.obj = obj elif isinstance(error, Exception): error = XMLSchemaValidationError(self, obj, str(error), source, namespaces) else: error = XMLSchemaValidationError(self, obj, error, source, namespaces) if validation == 'strict' and error.elem is not None: raise error return error def _parse_xpath_default_namespace(self, elem: ElementType) -> str: """ Parse XSD 1.1 xpathDefaultNamespace attribute for schema, alternative, assert, assertion and selector declarations, checking if the value is conforming to the specification. In case the attribute is missing or for wrong attribute values defaults to ''. """ try: value = elem.attrib['xpathDefaultNamespace'] except KeyError: return '' value = value.strip() if value == '##local': return '' elif value == '##defaultNamespace': default_namespace = getattr(self, 'default_namespace', None) return default_namespace if isinstance(default_namespace, str) else '' elif value == '##targetNamespace': target_namespace = getattr(self, 'target_namespace', '') return target_namespace if isinstance(target_namespace, str) else '' elif len(value.split()) == 1: return value else: admitted_values = ('##defaultNamespace', '##targetNamespace', '##local') msg = "wrong value %r for 'xpathDefaultNamespace' attribute, can be (anyURI | %s)." self.parse_error(msg % (value, ' | '.join(admitted_values)), elem) return '' class XsdComponent(XsdValidator): """ Class for XSD components. See: https://www.w3.org/TR/xmlschema-ref/ :param elem: ElementTree's node containing the definition. :param schema: the XMLSchema object that owns the definition. :param parent: the XSD parent, `None` means that is a global component that \ has the schema as parent. :param name: name of the component, maybe overwritten by the parse of the `elem` argument. :cvar qualified: for name matching, unqualified matching may be admitted only \ for elements and attributes. :vartype qualified: bool """ _REGEX_SPACE = re.compile(r'\s') _REGEX_SPACES = re.compile(r'\s+') _ADMITTED_TAGS: Union[Set[str], Tuple[str, ...], Tuple[()]] = () elem: etree_element parent = None name = None ref: Optional['XsdComponent'] = None qualified = True redefine = None _annotation = None _target_namespace: Optional[str] def __init__(self, elem: etree_element, schema: SchemaType, parent: Optional['XsdComponent'] = None, name: Optional[str] = None) -> None: super(XsdComponent, self).__init__(schema.validation) if name: self.name = name if parent is not None: self.parent = parent self.schema = schema self.maps: XsdGlobals = schema.maps self.elem = elem def __setattr__(self, name: str, value: Any) -> None: if name == 'elem': if value.tag not in self._ADMITTED_TAGS: msg = "wrong XSD element {!r} for {!r}, must be one of {!r}" raise XMLSchemaValueError( msg.format(value.tag, self.__class__, self._ADMITTED_TAGS) ) super(XsdComponent, self).__setattr__(name, value) if self.errors: self.errors.clear() self._parse() else: super(XsdComponent, self).__setattr__(name, value) @property def xsd_version(self) -> str: return self.schema.XSD_VERSION def is_global(self) -> bool: """Returns `True` if the instance is a global component, `False` if it's local.""" return self.parent is None def is_override(self) -> bool: """Returns `True` if the instance is an override of a global component.""" if self.parent is not None: return False return any(self.elem in x for x in self.schema.root if x.tag == XSD_OVERRIDE) @property def schema_elem(self) -> ElementType: """The reference element of the schema for the component instance.""" return self.elem @property def source(self) -> XMLResource: """Property that references to schema source.""" return self.schema.source @property def target_namespace(self) -> str: """Property that references to schema's targetNamespace.""" return self.schema.target_namespace if self.ref is None else self.ref.target_namespace @property def default_namespace(self) -> Optional[str]: """Property that references to schema's default namespaces.""" return self.schema.namespaces.get('') @property def namespaces(self) -> NamespacesType: """Property that references to schema's namespace mapping.""" return self.schema.namespaces @property def any_type(self) -> 'XsdComplexType': """Property that references to the xs:anyType instance of the global maps.""" return cast('XsdComplexType', self.maps.types[XSD_ANY_TYPE]) @property def any_simple_type(self) -> 'XsdSimpleType': """Property that references to the xs:anySimpleType instance of the global maps.""" return cast('XsdSimpleType', self.maps.types[XSD_ANY_SIMPLE_TYPE]) @property def any_atomic_type(self) -> 'XsdSimpleType': """Property that references to the xs:anyAtomicType instance of the global maps.""" return cast('XsdSimpleType', self.maps.types[XSD_ANY_ATOMIC_TYPE]) @property def annotation(self) -> Optional['XsdAnnotation']: if '_annotation' not in self.__dict__: for child in self.elem: if child.tag == XSD_ANNOTATION: self._annotation = XsdAnnotation(child, self.schema, self) break elif not callable(child.tag): self._annotation = None break else: self._annotation = None return self._annotation def __repr__(self) -> str: if self.ref is not None: return '%s(ref=%r)' % (self.__class__.__name__, self.prefixed_name) else: return '%s(name=%r)' % (self.__class__.__name__, self.prefixed_name) def _parse(self) -> None: return def _parse_reference(self) -> Optional[bool]: """ Helper method for referable components. Returns `True` if a valid reference QName is found without any error, otherwise returns `None`. Sets an id-related name for the component ('nameless_<id of the instance>') if both the attributes 'ref' and 'name' are missing. """ ref = self.elem.get('ref') if ref is None: if 'name' in self.elem.attrib: return None elif self.parent is None: self.parse_error("missing attribute 'name' in a global %r" % type(self)) else: self.parse_error( "missing both attributes 'name' and 'ref' in local %r" % type(self) ) elif 'name' in self.elem.attrib: self.parse_error("attributes 'name' and 'ref' are mutually exclusive") elif self.parent is None: self.parse_error("attribute 'ref' not allowed in a global %r" % type(self)) else: try: self.name = self.schema.resolve_qname(ref) except (KeyError, ValueError, RuntimeError) as err: self.parse_error(err) else: if self._parse_child_component(self.elem, strict=False) is not None: self.parse_error("a reference component cannot have " "child definitions/declarations") return True return None def _parse_child_component(self, elem: ElementType, strict: bool = True) \ -> Optional[ElementType]: child = None for e in elem: if e.tag == XSD_ANNOTATION or callable(e.tag): continue elif not strict: return e elif child is not None: msg = "too many XSD components, unexpected {!r} found at position {}" self.parse_error(msg.format(child, elem[:].index(e)), elem) break else: child = e return child def _parse_target_namespace(self) -> None: """ XSD 1.1 targetNamespace attribute in elements and attributes declarations. """ if 'targetNamespace' not in self.elem.attrib: return self._target_namespace = self.elem.attrib['targetNamespace'].strip() if 'name' not in self.elem.attrib: self.parse_error("attribute 'name' must be present when " "'targetNamespace' attribute is provided") if 'form' in self.elem.attrib: self.parse_error("attribute 'form' must be absent when " "'targetNamespace' attribute is provided") if self._target_namespace != self.schema.target_namespace: if self.parent is None: self.parse_error("a global %s must have the same namespace as " "its parent schema" % self.__class__.__name__) xsd_type = self.get_parent_type() if xsd_type is None or xsd_type.parent is not None: pass elif xsd_type.derivation != 'restriction' or \ getattr(xsd_type.base_type, 'name', None) == XSD_ANY_TYPE: self.parse_error("a declaration contained in a global complexType " "must have the same namespace as its parent schema") if self.name is None: pass # pragma: no cover elif not self._target_namespace: self.name = local_name(self.name) else: self.name = '{%s}%s' % (self._target_namespace, local_name(self.name)) @property def local_name(self) -> Optional[str]: """The local part of the name of the component, or `None` if the name is `None`.""" return None if self.name is None else local_name(self.name) @property def qualified_name(self) -> Optional[str]: """The name of the component in extended format, or `None` if the name is `None`.""" return None if self.name is None else get_qname(self.target_namespace, self.name) @property def prefixed_name(self) -> Optional[str]: """The name of the component in prefixed format, or `None` if the name is `None`.""" return None if self.name is None else get_prefixed_qname(self.name, self.namespaces) @property def id(self) -> Optional[str]: """The ``'id'`` attribute of the component tag, ``None`` if missing.""" return self.elem.get('id') @property def validation_attempted(self) -> str: return 'full' if self.built else 'partial' def build(self) -> None: """ Builds components that are not fully parsed at initialization, like model groups or internal local elements in model groups. Otherwise does nothing. """ @property def built(self) -> bool: raise NotImplementedError() def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None, **kwargs: Any) -> bool: """ Returns `True` if the component name is matching the name provided as argument, `False` otherwise. For XSD elements the matching is extended to substitutes. :param name: a local or fully-qualified name. :param default_namespace: used if it's not None and not empty for completing \ the name argument in case it's a local name. :param kwargs: additional options that can be used by certain components. """ if not name: return self.name == name elif name[0] == '{': return self.qualified_name == name elif not default_namespace: return self.name == name or not self.qualified and self.local_name == name else: qname = '{%s}%s' % (default_namespace, name) return self.qualified_name == qname or not self.qualified and self.local_name == name def match(self, name: Optional[str], default_namespace: Optional[str] = None, **kwargs: Any) -> Optional['XsdComponent']: """ Returns the component if its name is matching the name provided as argument, `None` otherwise. """ return self if self.is_matching(name, default_namespace, **kwargs) else None def get_matching_item(self, mapping: MutableMapping[str, Any], ns_prefix: str = 'xmlns', match_local_name: bool = False) -> Optional[Any]: """ If a key is matching component name, returns its value, otherwise returns `None`. """ if self.name is None: return None elif not self.target_namespace: return mapping.get(self.name) elif self.qualified_name in mapping: return mapping[cast(str, self.qualified_name)] elif self.prefixed_name in mapping: return mapping[cast(str, self.prefixed_name)] # Try a match with other prefixes target_namespace = self.target_namespace suffix = ':%s' % self.local_name for k in filter(lambda x: x.endswith(suffix), mapping): prefix = k.split(':')[0] if self.namespaces.get(prefix) == target_namespace: return mapping[k] # Match namespace declaration within value ns_declaration = '{}:{}'.format(ns_prefix, prefix) try: if mapping[k][ns_declaration] == target_namespace: return mapping[k] except (KeyError, TypeError): pass else: if match_local_name: return mapping.get(self.local_name) # type: ignore[arg-type] return None def get_global(self) -> 'XsdComponent': """Returns the global XSD component that contains the component instance.""" if self.parent is None: return self component = self.parent while component is not self: # pragma: no cover if component.parent is None: return component component = component.parent else: raise XMLSchemaValueError(f"parent circularity from {self}") # pragma: no cover def get_parent_type(self) -> Optional['XsdType']: """ Returns the nearest XSD type that contains the component instance, or `None` if the component doesn't have an XSD type parent. """ component = self.parent while component is not self and component is not None: if isinstance(component, XsdType): return component component = component.parent return None def iter_components(self, xsd_classes: ComponentClassType = None) \ -> Iterator['XsdComponent']: """ Creates an iterator for XSD subcomponents. :param xsd_classes: provide a class or a tuple of classes to iterates over only a \ specific classes of components. """ if xsd_classes is None or isinstance(self, xsd_classes): yield self def iter_ancestors(self, xsd_classes: ComponentClassType = None)\ -> Iterator['XsdComponent']: """ Creates an iterator for XSD ancestor components, schema excluded. Stops when the component is global or if the ancestor is not an instance of the specified class/classes. :param xsd_classes: provide a class or a tuple of classes to iterates over only a \ specific classes of components. """ ancestor = self while True: if ancestor.parent is None: break ancestor = ancestor.parent if xsd_classes is not None and not isinstance(ancestor, xsd_classes): break yield ancestor def tostring(self, indent: str = '', max_lines: Optional[int] = None, spaces_for_tab: int = 4) -> Union[str, bytes]: """Serializes the XML elements that declare or define the component to a string.""" return etree_tostring(self.schema_elem, self.namespaces, indent, max_lines, spaces_for_tab) class XsdAnnotation(XsdComponent): """ Class for XSD *annotation* definitions. :ivar appinfo: a list containing the xs:appinfo children. :ivar documentation: a list containing the xs:documentation children. .. <annotation id = ID {any attributes with non-schema namespace . . .}> Content: (appinfo | documentation)* </annotation> .. <appinfo source = anyURI {any attributes with non-schema namespace . . .}> Content: ({any})* </appinfo> .. <documentation source = anyURI xml:lang = language {any attributes with non-schema namespace . . .}> Content: ({any})* </documentation> """ _ADMITTED_TAGS = {XSD_ANNOTATION} annotation = None def __repr__(self) -> str: return '%s(%r)' % (self.__class__.__name__, str(self)[:40]) def __str__(self) -> str: return '\n'.join(elementpath.select(self.elem, '*/fn:string()')) @property def built(self) -> bool: return True def _parse(self) -> None: self.appinfo = [] self.documentation = [] for child in self.elem: if child.tag == XSD_APPINFO: self.appinfo.append(child) elif child.tag == XSD_DOCUMENTATION: self.documentation.append(child) class XsdType(XsdComponent): """Common base class for XSD types.""" abstract = False base_type: Optional[BaseXsdType] = None derivation: Optional[str] = None _final: Optional[str] = None @property def final(self) -> str: return self.schema.final_default if self._final is None else self._final @property def built(self) -> bool: raise NotImplementedError() @property def content_type_label(self) -> str: """The content type classification.""" raise NotImplementedError() @property def sequence_type(self) -> str: """The XPath sequence type associated with the content.""" raise NotImplementedError() @property def root_type(self) -> BaseXsdType: """ The root type of the type definition hierarchy. For an atomic type is the primitive type. For a list is the primitive type of the item. For a union is the base union type. For a complex type is xs:anyType. """ if getattr(self, 'attributes', None): return cast('XsdComplexType', self.maps.types[XSD_ANY_TYPE]) elif self.base_type is None: if self.is_simple(): return cast('XsdSimpleType', self) return cast('XsdComplexType', self.maps.types[XSD_ANY_TYPE]) primitive_type: BaseXsdType try: if self.base_type.is_simple(): primitive_type = self.base_type.primitive_type # type: ignore[union-attr] else: primitive_type = self.base_type.content.primitive_type # type: ignore[union-attr] except AttributeError: # The type has complex or XsdList content return self.base_type.root_type else: return primitive_type @property def simple_type(self) -> Optional['XsdSimpleType']: """ Property that is the instance itself for a simpleType. For a complexType is the instance's *content* if this is a simpleType or `None` if the instance's *content* is a model group. """ raise NotImplementedError() @property def model_group(self) -> Optional['XsdGroup']: """ Property that is `None` for a simpleType. For a complexType is the instance's *content* if this is a model group or `None` if the instance's *content* is a simpleType. """ return None @staticmethod def is_simple() -> bool: """Returns `True` if the instance is a simpleType, `False` otherwise.""" raise NotImplementedError() @staticmethod def is_complex() -> bool: """Returns `True` if the instance is a complexType, `False` otherwise.""" def is_atomic(self) -> bool: """Returns `True` if the instance is an atomic simpleType, `False` otherwise.""" return False def is_list(self) -> bool: """Returns `True` if the instance is a list simpleType, `False` otherwise.""" return False def is_union(self) -> bool: """Returns `True` if the instance is a union simpleType, `False` otherwise.""" return False def is_datetime(self) -> bool: """ Returns `True` if the instance is a datetime/duration XSD builtin-type, `False` otherwise. """ return False def is_empty(self) -> bool: """Returns `True` if the instance has an empty content, `False` otherwise.""" raise NotImplementedError() def is_emptiable(self) -> bool: """Returns `True` if the instance has an emptiable value or content, `False` otherwise.""" raise NotImplementedError() def has_simple_content(self) -> bool: """ Returns `True` if the instance has a simple content, `False` otherwise. """ raise NotImplementedError() def has_complex_content(self) -> bool: """ Returns `True` if the instance is a complexType with mixed or element-only content, `False` otherwise. """ raise NotImplementedError() def has_mixed_content(self) -> bool: """ Returns `True` if the instance is a complexType with mixed content, `False` otherwise. """ raise NotImplementedError() def is_element_only(self) -> bool: """ Returns `True` if the instance is a complexType with element-only content, `False` otherwise. """ raise NotImplementedError() def is_derived(self, other: Union[BaseXsdType, Tuple[ElementType, SchemaType]], derivation: Optional[str] = None) -> bool: """ Returns `True` if the instance is derived from *other*, `False` otherwise. The optional argument derivation can be a string containing the words 'extension' or 'restriction' or both. """ raise NotImplementedError() def is_extension(self) -> bool: return self.derivation == 'extension' def is_restriction(self) -> bool: return self.derivation == 'restriction' def is_blocked(self, xsd_element: 'XsdElement') -> bool: """ Returns `True` if the base type derivation is blocked, `False` otherwise. """ xsd_type = xsd_element.type if self is xsd_type: return False block = ('%s %s' % (xsd_element.block, xsd_type.block)).strip() if not block: return False _block = {x for x in block.split() if x in ('extension', 'restriction')} return any(self.is_derived(xsd_type, derivation) for derivation in _block) def is_dynamic_consistent(self, other: Any) -> bool: return other.name == XSD_ANY_TYPE or self.is_derived(other) or \ hasattr(other, 'member_types') and \ any(self.is_derived(mt) for mt in other.member_types) # pragma: no cover def is_key(self) -> bool: return self.name == XSD_ID or self.is_derived(self.maps.types[XSD_ID]) def is_qname(self) -> bool: return self.name == XSD_QNAME or self.is_derived(self.maps.types[XSD_QNAME]) def is_notation(self) -> bool: return self.name == XSD_NOTATION_TYPE or self.is_derived(self.maps.types[XSD_NOTATION_TYPE]) def is_decimal(self) -> bool: return self.name == XSD_DECIMAL or self.is_derived(self.maps.types[XSD_DECIMAL]) def text_decode(self, text: str) -> Any: raise NotImplementedError() ST = TypeVar('ST') DT = TypeVar('DT') class ValidationMixin(Generic[ST, DT]): """ Mixin for implementing XML data validators/decoders on XSD components. A derived class must implement the methods `iter_decode` and `iter_encode`. """ def validate(self, obj: ST, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> None: """ Validates XML data against the XSD schema/component instance. :param obj: the XML data. Can be a string for an attribute or a simple type \ validators, or an ElementTree's Element otherwise. :param use_defaults: indicates whether to use default values for filling missing data. :param namespaces: is an optional mapping from namespace prefix to URI. :param max_depth: maximum level of validation, for default there is no limit. :param extra_validator: an optional function for performing non-standard \ validations on XML data. The provided function is called for each traversed \ element, with the XML element as 1st argument and the corresponding XSD \ element as 2nd argument. It can be also a generator function and has to \ raise/yield :exc:`XMLSchemaValidationError` exceptions. :raises: :exc:`XMLSchemaValidationError` if the XML data instance is invalid. """ for error in self.iter_errors(obj, use_defaults, namespaces, max_depth, extra_validator): raise error def is_valid(self, obj: ST, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) -> bool: """ Like :meth:`validate` except that does not raise an exception but returns ``True`` if the XML data instance is valid, ``False`` if it is invalid. """ error = next(self.iter_errors(obj, use_defaults, namespaces, max_depth, extra_validator), None) return error is None def iter_errors(self, obj: ST, use_defaults: bool = True, namespaces: Optional[NamespacesType] = None, max_depth: Optional[int] = None, extra_validator: Optional[ExtraValidatorType] = None) \ -> Iterator[XMLSchemaValidationError]: """ Creates an iterator for the errors generated by the validation of an XML data against the XSD schema/component instance. Accepts the same arguments of :meth:`validate`. """ kwargs: Dict[str, Any] = { 'use_defaults': use_defaults, 'namespaces': namespaces, } if max_depth is not None: kwargs['max_depth'] = max_depth if extra_validator is not None: kwargs['extra_validator'] = extra_validator for result in self.iter_decode(obj, **kwargs): if isinstance(result, XMLSchemaValidationError): yield result else: del result def decode(self, obj: ST, validation: str = 'strict', **kwargs: Any) -> DecodeType[DT]: """ Decodes XML data. :param obj: the XML data. Can be a string for an attribute or for simple type \ components or a dictionary for an attribute group or an ElementTree's \ Element for other components. :param validation: the validation mode. Can be 'lax', 'strict' or 'skip. :param kwargs: optional keyword arguments for the method :func:`iter_decode`. :return: a dictionary like object if the XSD component is an element, a \ group or a complex type; a list if the XSD component is an attribute group; \ a simple data type object otherwise. If *validation* argument is 'lax' a 2-items \ tuple is returned, where the first item is the decoded object and the second item \ is a list containing the errors. :raises: :exc:`XMLSchemaValidationError` if the object is not decodable by \ the XSD component, or also if it's invalid when ``validation='strict'`` is provided. """ check_validation_mode(validation) result: Union[DT, XMLSchemaValidationError] errors: List[XMLSchemaValidationError] = [] for result in self.iter_decode(obj, validation, **kwargs): # pragma: no cover if not isinstance(result, XMLSchemaValidationError): return (result, errors) if validation == 'lax' else result elif validation == 'strict': raise result else: errors.append(result) return (None, errors) if validation == 'lax' else None # fallback: pragma: no cover def encode(self, obj: Any, validation: str = 'strict', **kwargs: Any) -> EncodeType[Any]: """ Encodes data to XML. :param obj: the data to be encoded to XML. :param validation: the validation mode. Can be 'lax', 'strict' or 'skip. :param kwargs: optional keyword arguments for the method :func:`iter_encode`. :return: An element tree's Element if the original data is a structured data or \ a string if it's simple type datum. If *validation* argument is 'lax' a 2-items \ tuple is returned, where the first item is the encoded object and the second item \ is a list containing the errors. :raises: :exc:`XMLSchemaValidationError` if the object is not encodable by the XSD \ component, or also if it's invalid when ``validation='strict'`` is provided. """ check_validation_mode(validation) result, errors = None, [] for result in self.iter_encode(obj, validation=validation, **kwargs): # pragma: no cover if not isinstance(result, XMLSchemaValidationError): break elif validation == 'strict': raise result else: errors.append(result) return (result, errors) if validation == 'lax' else result def iter_decode(self, obj: ST, validation: str = 'lax', **kwargs: Any) \ -> IterDecodeType[DT]: """ Creates an iterator for decoding an XML source to a Python object. :param obj: the XML data. :param validation: the validation mode. Can be 'lax', 'strict' or 'skip. :param kwargs: keyword arguments for the decoder API. :return: Yields a decoded object, eventually preceded by a sequence of \ validation or decoding errors. """ raise NotImplementedError() def iter_encode(self, obj: Any, validation: str = 'lax', **kwargs: Any) \ -> IterEncodeType[Any]: """ Creates an iterator for encoding data to an Element tree. :param obj: The data that has to be encoded. :param validation: The validation mode. Can be 'lax', 'strict' or 'skip'. :param kwargs: keyword arguments for the encoder API. :return: Yields an Element, eventually preceded by a sequence of validation \ or encoding errors. """ raise NotImplementedError() ����������������������������������������������������������������������������������������������������������������������������xmlschema-1.10.0/xmlschema/xpath.py�����������������������������������������������������������������0000664�0000000�0000000�00000033704�14211403446�0017237�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # Copyright (c), 2016-2020, SISSA (International School for Advanced Studies). # All rights reserved. # This file is distributed under the terms of the MIT License. # See the file 'LICENSE' in the root directory of the present # distribution, or http://opensource.org/licenses/MIT. # # @author Davide Brunato <brunato@sissa.it> # """ This module defines a proxy class and a mixin class for enabling XPath on schemas. """ import sys from abc import abstractmethod from typing import cast, overload, Any, Dict, Iterator, List, Optional, \ Sequence, Set, TypeVar, Union import re from elementpath import TypedElement, XPath2Parser, \ XPathSchemaContext, AbstractSchemaProxy, protocols from .exceptions import XMLSchemaValueError, XMLSchemaTypeError from .names import XSD_NAMESPACE from .aliases import NamespacesType, SchemaType, BaseXsdType, XPathElementType from .helpers import get_qname, local_name, get_prefixed_qname if sys.version_info < (3, 8): XMLSchemaProtocol = SchemaType ElementProtocol = XPathElementType XsdTypeProtocol = BaseXsdType else: from typing import runtime_checkable, Protocol XsdTypeProtocol = protocols.XsdTypeProtocol class XMLSchemaProtocol(protocols.XMLSchemaProtocol, Protocol): attributes: Dict[str, Any] @runtime_checkable class ElementProtocol(protocols.ElementProtocol, Protocol): schema: XMLSchemaProtocol attributes: Dict[str, Any] _REGEX_TAG_POSITION = re.compile(r'\b\[\d+]') def iter_schema_nodes(root: Union[XMLSchemaProtocol, ElementProtocol], with_root: bool = True) \ -> Iterator[Union[XMLSchemaProtocol, ElementProtocol]]: """ Iteration function for schema nodes. It doesn't yield text nodes, that are always `None` for schema elements, and detects visited element in order to skip already visited nodes. :param root: schema or schema element. :param with_root: if `True` yields initial element. """ if isinstance(root, TypedElement): root = cast(ElementProtocol, root.elem) nodes = {root} if with_root: yield root iterators: List[Any] = [] children: Iterator[Any] = iter(root) while True: try: child = next(children) except StopIteration: try: children = iterators.pop() except IndexError: return else: if child in nodes: continue elif child.ref is not None: nodes.add(child) yield child if child.ref not in nodes: nodes.add(child.ref) yield child.ref iterators.append(children) children = iter(child.ref) else: nodes.add(child) yield child iterators.append(children) children = iter(child) class XMLSchemaContext(XPathSchemaContext): """XPath dynamic schema context for the *xmlschema* library.""" _iter_nodes = staticmethod(iter_schema_nodes) class XMLSchemaProxy(AbstractSchemaProxy): """XPath schema proxy for the *xmlschema* library.""" _schema: SchemaType # type: ignore[assignment] def __init__(self, schema: Optional[XMLSchemaProtocol] = None, base_element: Optional[ElementProtocol] = None) -> None: if schema is None: from xmlschema import XMLSchema10 schema = cast(XMLSchemaProtocol, getattr(XMLSchema10, 'meta_schema', None)) super(XMLSchemaProxy, self).__init__(schema, base_element) if base_element is not None: try: if base_element.schema is not schema: raise XMLSchemaValueError("%r is not an element of %r" % (base_element, schema)) except AttributeError: raise XMLSchemaTypeError("%r is not an XsdElement" % base_element) def bind_parser(self, parser: XPath2Parser) -> None: parser.schema = self parser.symbol_table = dict(parser.__class__.symbol_table) with self._schema.lock: if self._schema.xpath_tokens is None: self._schema.xpath_tokens = { xsd_type.name: parser.schema_constructor(xsd_type.name) for xsd_type in self.iter_atomic_types() if xsd_type.name } parser.symbol_table.update(self._schema.xpath_tokens) def get_context(self) -> XMLSchemaContext: return XMLSchemaContext( root=self._schema, # type: ignore[arg-type] namespaces=dict(self._schema.namespaces), item=self._base_element ) def is_instance(self, obj: Any, type_qname: str) -> bool: # FIXME: use elementpath.datatypes for checking atomic datatypes xsd_type = self._schema.maps.types[type_qname] if isinstance(xsd_type, tuple): from .validators import XMLSchemaNotBuiltError raise XMLSchemaNotBuiltError(xsd_type[1], f"XSD type {type_qname} is not built") try: xsd_type.encode(obj) except ValueError: return False else: return True def cast_as(self, obj: Any, type_qname: str) -> Any: xsd_type = self._schema.maps.types[type_qname] if isinstance(xsd_type, tuple): from .validators import XMLSchemaNotBuiltError raise XMLSchemaNotBuiltError(xsd_type[1], f"XSD type {type_qname} is not built") return xsd_type.decode(obj) def iter_atomic_types(self) -> Iterator[XsdTypeProtocol]: for xsd_type in self._schema.maps.types.values(): if not isinstance(xsd_type, tuple) and \ xsd_type.target_namespace != XSD_NAMESPACE and \ hasattr(xsd_type, 'primitive_type'): yield cast(XsdTypeProtocol, xsd_type) def get_primitive_type(self, xsd_type: XsdTypeProtocol) -> XsdTypeProtocol: primitive_type = cast(BaseXsdType, xsd_type).root_type return cast(XsdTypeProtocol, primitive_type) E = TypeVar('E', bound='ElementPathMixin[Any]') class ElementPathMixin(Sequence[E]): """ Mixin abstract class for enabling ElementTree and XPath 2.0 API on XSD components. :cvar text: the Element text, for compatibility with the ElementTree API. :cvar tail: the Element tail, for compatibility with the ElementTree API. """ text: Optional[str] = None tail: Optional[str] = None name: Optional[str] = None attributes: Any = {} namespaces: Any = {} xpath_default_namespace = '' @abstractmethod def __iter__(self) -> Iterator[E]: raise NotImplementedError @overload def __getitem__(self, i: int) -> E: ... @overload def __getitem__(self, s: slice) -> Sequence[E]: ... def __getitem__(self, i: Union[int, slice]) -> Union[E, Sequence[E]]: try: return [e for e in self][i] except IndexError: raise IndexError('child index out of range') def __reversed__(self) -> Iterator[E]: return reversed([e for e in self]) def __len__(self) -> int: return len([e for e in self]) @property def tag(self) -> str: """Alias of the *name* attribute. For compatibility with the ElementTree API.""" return self.name or '' @property def attrib(self) -> Any: """Returns the Element attributes. For compatibility with the ElementTree API.""" return self.attributes def get(self, key: str, default: Any = None) -> Any: """Gets an Element attribute. For compatibility with the ElementTree API.""" return self.attributes.get(key, default) @property def xpath_proxy(self) -> XMLSchemaProxy: """Returns an XPath proxy instance bound with the schema.""" raise NotImplementedError def _get_xpath_namespaces(self, namespaces: Optional[NamespacesType] = None) \ -> Dict[str, str]: """ Returns a dictionary with namespaces for XPath selection. :param namespaces: an optional map from namespace prefix to namespace URI. \ If this argument is not provided the schema's namespaces are used. """ if namespaces is None: namespaces = {k: v for k, v in self.namespaces.items() if k} namespaces[''] = self.xpath_default_namespace elif '' not in namespaces: namespaces[''] = self.xpath_default_namespace xpath_namespaces: Dict[str, str] = XPath2Parser.DEFAULT_NAMESPACES.copy() xpath_namespaces.update(namespaces) return xpath_namespaces def is_matching(self, name: Optional[str], default_namespace: Optional[str] = None) -> bool: if not name or name[0] == '{' or not default_namespace: return self.name == name else: return self.name == '{%s}%s' % (default_namespace, name) def find(self, path: str, namespaces: Optional[NamespacesType] = None) -> Optional[E]: """ Finds the first XSD subelement matching the path. :param path: an XPath expression that considers the XSD component as the root element. :param namespaces: an optional mapping from namespace prefix to namespace URI. :return: the first matching XSD subelement or ``None`` if there is no match. """ path = _REGEX_TAG_POSITION.sub('', path.strip()) # Strips tags positions from path namespaces = self._get_xpath_namespaces(namespaces) parser = XPath2Parser(namespaces, strict=False) context = XMLSchemaContext(self) # type: ignore[arg-type] return cast(Optional[E], next(parser.parse(path).select_results(context), None)) def findall(self, path: str, namespaces: Optional[NamespacesType] = None) -> List[E]: """ Finds all XSD subelements matching the path. :param path: an XPath expression that considers the XSD component as the root element. :param namespaces: an optional mapping from namespace prefix to full name. :return: a list containing all matching XSD subelements in document order, an empty \ list is returned if there is no match. """ path = _REGEX_TAG_POSITION.sub('', path.strip()) # Strips tags positions from path namespaces = self._get_xpath_namespaces(namespaces) parser = XPath2Parser(namespaces, strict=False) context = XMLSchemaContext(self) # type: ignore[arg-type] return cast(List[E], parser.parse(path).get_results(context)) def iterfind(self, path: str, namespaces: Optional[NamespacesType] = None) -> Iterator[E]: """ Creates and iterator for all XSD subelements matching the path. :param path: an XPath expression that considers the XSD component as the root element. :param namespaces: is an optional mapping from namespace prefix to full name. :return: an iterable yielding all matching XSD subelements in document order. """ path = _REGEX_TAG_POSITION.sub('', path.strip()) # Strips tags positions from path namespaces = self._get_xpath_namespaces(namespaces) parser = XPath2Parser(namespaces, strict=False) context = XMLSchemaContext(self) # type: ignore[arg-type] return cast(Iterator[E], parser.parse(path).select_results(context)) def iter(self, tag: Optional[str] = None) -> Iterator[E]: """ Creates an iterator for the XSD element and its subelements. If tag is not `None` or '*', only XSD elements whose matches tag are returned from the iterator. Local elements are expanded without repetitions. Element references are not expanded because the global elements are not descendants of other elements. """ def safe_iter(elem: Any) -> Iterator[E]: if tag is None or elem.is_matching(tag): yield elem for child in elem: if child.parent is None: yield from safe_iter(child) elif getattr(child, 'ref', None) is not None: if tag is None or child.is_matching(tag): yield child elif child not in local_elements: local_elements.add(child) yield from safe_iter(child) if tag == '*': tag = None local_elements: Set[E] = set() return safe_iter(self) def iterchildren(self, tag: Optional[str] = None) -> Iterator[E]: """ Creates an iterator for the child elements of the XSD component. If *tag* is not `None` or '*', only XSD elements whose name matches tag are returned from the iterator. """ if tag == '*': tag = None for child in self: if tag is None or child.is_matching(tag): yield child class XPathElement(ElementPathMixin['XPathElement']): """An element node for making XPath operations on schema types.""" name: str parent = None def __init__(self, name: str, xsd_type: BaseXsdType) -> None: self.name = name self.type = xsd_type self.attributes = getattr(xsd_type, 'attributes', {}) def __iter__(self) -> Iterator['XPathElement']: if not self.type.has_simple_content(): yield from self.type.content.iter_elements() # type: ignore[union-attr] @property def xpath_proxy(self) -> XMLSchemaProxy: return XMLSchemaProxy( cast(XMLSchemaProtocol, self.schema), cast(ElementProtocol, self) ) @property def schema(self) -> SchemaType: return self.type.schema @property def target_namespace(self) -> str: return self.type.schema.target_namespace @property def namespaces(self) -> NamespacesType: return self.type.schema.namespaces @property def local_name(self) -> str: return local_name(self.name) @property def qualified_name(self) -> str: return get_qname(self.target_namespace, self.name) @property def prefixed_name(self) -> str: return get_prefixed_qname(self.name, self.namespaces) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������