# HG changeset patch # User Paul Boddie # Date 1220139091 -7200 # Node ID 12307bf68e06dc306b5509c0b4edbf598c51217d # Parent 250a286e47eca819e3aa47d62a4bb7c34f1329d1 Added Relax-NG validation support. Added DOMConfiguration support to the _Document class, adding an error handler (DOMErrorHandler, new in libxml2dom.errors) to deal with validation errors and warnings. Added missing parser context disposal. Switched DOMException usage to specific xml.dom exception usage. Updated release notes. diff -r 250a286e47ec -r 12307bf68e06 README.txt --- a/README.txt Sat Aug 30 00:51:04 2008 +0200 +++ b/README.txt Sun Aug 31 01:31:31 2008 +0200 @@ -77,6 +77,7 @@ * Introduced support for validation, together with the libxml2dom.errors module. * Improved error messages related to parsing. + * Added DOMConfiguration support to documents. New in libxml2dom 0.4.6 (Changes since libxml2dom 0.4.5) -------------------------------------------------------- diff -r 250a286e47ec -r 12307bf68e06 libxml2dom/__init__.py --- a/libxml2dom/__init__.py Sat Aug 30 00:51:04 2008 +0200 +++ b/libxml2dom/__init__.py Sun Aug 31 01:31:31 2008 +0200 @@ -29,6 +29,7 @@ toString as Node_toString, toStream as Node_toStream, \ toFile as Node_toFile import urllib # for parseURI in HTML mode +import libxml2dom.errors # Standard namespaces. @@ -392,9 +393,9 @@ def insertBefore(self, tmp, oldNode): if tmp.ownerDocument != self.ownerDocument: - raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) + raise xml.dom.WrongDocumentErr() if oldNode.parentNode != self: - raise xml.dom.DOMException(xml.dom.NOT_FOUND_ERR) + raise xml.dom.NotFoundErr() if hasattr(tmp, "as_native_node"): return self.impl.get_node(Node_insertBefore(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) else: @@ -402,9 +403,9 @@ def replaceChild(self, tmp, oldNode): if tmp.ownerDocument != self.ownerDocument: - raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) + raise xml.dom.WrongDocumentErr() if oldNode.parentNode != self: - raise xml.dom.DOMException(xml.dom.NOT_FOUND_ERR) + raise xml.dom.NotFoundErr() if hasattr(tmp, "as_native_node"): return self.impl.get_node(Node_replaceChild(self._node, tmp.as_native_node(), oldNode.as_native_node()), self) else: @@ -412,7 +413,7 @@ def appendChild(self, tmp): if tmp.ownerDocument != self.ownerDocument: - raise xml.dom.DOMException(xml.dom.WRONG_DOCUMENT_ERR) + raise xml.dom.WrongDocumentErr() if hasattr(tmp, "as_native_node"): return self.impl.get_node(Node_appendChild(self._node, tmp.as_native_node()), self) else: @@ -558,12 +559,23 @@ """ An abstract class providing document-level housekeeping and distinct - functionality. + functionality. Configuration of the document is also supported. + See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#DOMConfiguration """ + # Constants from + # See: http://www.w3.org/TR/DOM-Level-3-Val/validation.html#VAL-Interfaces-NodeEditVAL + + VAL_TRUE = 5 + VAL_FALSE = 6 + VAL_UNKNOWN = 7 + def __init__(self, node, impl): self._node = node self.implementation = self.impl = impl + self.error_handler = libxml2dom.errors.DOMErrorHandler() + + # Standard DOM properties and their implementations. def _documentElement(self): return self.xpath("*")[0] @@ -578,6 +590,53 @@ documentElement = property(_documentElement) ownerDocument = property(_ownerDocument) + # DOM Level 3 Core DOMConfiguration methods. + + def setParameter(self, name, value): + if name == "error-handler": + raise xml.dom.NotSupportedErr() + raise xml.dom.NotFoundErr() + + def getParameter(self, name): + if name == "error-handler": + return self.error_handler + raise xml.dom.NotFoundErr() + + def canSetParameter(self, name, value): + return 0 + + def _parameterNames(self): + return [] + + # Extensions to the usual PyXML API. + + def validate(self, doc): + + """ + Validate the document against the given schema document, 'doc'. + """ + + if hasattr(doc, "as_native_node"): + _schema = Document_schema(doc.as_native_node()) + else: + _schema = Document_schemaFromString(doc.toString()) + try: + self.error_handler.reset() + return Document_validate(_schema, self._node, self.error_handler) + finally: + Schema_free(_schema) + + # DOM Level 3 Validation methods. + + def validateDocument(self, doc): + + """ + Validate the document against the given schema document, 'doc'. + See: http://www.w3.org/TR/DOM-Level-3-Val/validation.html#VAL-Interfaces-DocumentEditVAL-validateDocument + """ + + return self.validate(doc) and self.VAL_TRUE or self.VAL_FALSE + class Document(_Document, Node): """ diff -r 250a286e47ec -r 12307bf68e06 libxml2dom/errors.py --- a/libxml2dom/errors.py Sat Aug 30 00:51:04 2008 +0200 +++ b/libxml2dom/errors.py Sun Aug 31 01:31:31 2008 +0200 @@ -2,7 +2,6 @@ """ Errors for DOM Level 3. -See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ERROR-Interfaces-DOMError Copyright (C) 2008 Paul Boddie @@ -22,7 +21,10 @@ class DOMError: - "DOM Level 3 Core exception." + """ + DOM Level 3 Core exception. + See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ERROR-Interfaces-DOMError + """ SEVERITY_WARNING = 1 SEVERITY_ERROR = 2 @@ -42,4 +44,30 @@ def __str__(self): return "DOMError: %s" % self.message +# NOTE: Find a reasonable way of exposing error details. + +class DOMErrorHandler: + + """ + DOM Level 3 Core error handler. + See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ERROR-Interfaces-DOMErrorHandler + """ + + def __init__(self): + self.errors = [] + + def handleError(self, error): + self.errors.append(error) + + # Special extension methods. + + def reset(self): + self.errors = [] + + def __repr__(self): + return "DOMErrorHandler()" + + def __str__(self): + return "DOMErrorHandler: %r" % self.errors + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 250a286e47ec -r 12307bf68e06 libxml2dom/macrolib/macrolib.py --- a/libxml2dom/macrolib/macrolib.py Sat Aug 30 00:51:04 2008 +0200 +++ b/libxml2dom/macrolib/macrolib.py Sun Aug 31 01:31:31 2008 +0200 @@ -459,7 +459,7 @@ elif Node_nodeType(other) == xml.dom.Node.CDATA_SECTION_NODE: return Node_createCDATASection(node, Node_data(other)) - raise xml.dom.DOMException(xml.dom.NOT_SUPPORTED_ERR, "Node type '%s' (%d) not supported." % (other, Node_nodeType(other))) + raise xml.dom.NotSupportedErr("Node type '%s' (%d) not supported." % (other, Node_nodeType(other))) def Node_importNode_DOM(node, other, deep): if other.nodeType == xml.dom.Node.ELEMENT_NODE: @@ -484,8 +484,7 @@ elif other.nodeType == xml.dom.Node.CDATA_SECTION_NODE: return Node_createCDATASection(node, other.data) - raise xml.dom.DOMException( - xml.dom.NOT_SUPPORTED_ERR, + raise xml.dom.NotSupportedErr( "Node type '%s' (%d) not supported." % (_reverseNodeTypes[other.nodeType], other.nodeType) ) @@ -637,6 +636,7 @@ finally: Parser_resetError(error) + libxml2mod.xmlFreeParserCtxt(context) def toString(node, encoding=None, prettyprint=0): return libxml2mod.serializeNode(node, encoding, prettyprint) @@ -735,4 +735,47 @@ def Parser_parse(context): libxml2mod.xmlParseDocument(context) +# Schema and validation helper functions and classes. + +def Document_schema(doc): + return Schema_parse(libxml2mod.xmlRelaxNGNewDocParserCtxt(doc)) + +def Document_schemaFromString(s): + return Schema_parse(libxml2mod.xmlRelaxNGNewMemParserCtxt(s, len(s))) + +def Document_validate(schema, doc, error_handler): + validator_context = libxml2mod.xmlRelaxNGNewValidCtxt(schema) + handler = ValidationHandler(error_handler) + libxml2mod.xmlRelaxNGSetValidErrors(validator_context, handler.error, handler.warning, None) + try: + status = libxml2mod.xmlRelaxNGValidateDoc(validator_context, doc) + return status == 0 + finally: + libxml2mod.xmlRelaxNGFreeValidCtxt(validator_context) + +def Schema_parse(context): + try: + return libxml2mod.xmlRelaxNGParse(context) + finally: + libxml2mod.xmlRelaxNGFreeParserCtxt(context) + +def Schema_free(schema): + libxml2mod.xmlRelaxNGFree(schema) + +class ValidationHandler: + + """ + A handler which collects validation errors and warnings and passes them to a + DOMErrorHandler. + """ + + def __init__(self, error_handler): + self.error_handler = error_handler + + def error(self, msg, arg): + self.error_handler.handleError(DOMError(DOMError.SEVERITY_FATAL_ERROR, msg.strip())) + + def warning(self, msg, arg): + self.error_handler.handleError(DOMError(DOMError.SEVERITY_WARNING, msg.strip())) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 250a286e47ec -r 12307bf68e06 packages/debian-etch/python-libxml2dom/debian/changelog --- a/packages/debian-etch/python-libxml2dom/debian/changelog Sat Aug 30 00:51:04 2008 +0200 +++ b/packages/debian-etch/python-libxml2dom/debian/changelog Sun Aug 31 01:31:31 2008 +0200 @@ -11,6 +11,7 @@ * Introduced support for validation, together with the libxml2dom.errors module. * Improved error messages related to parsing. + * Added DOMConfiguration support to documents. -- Paul Boddie Tue, 26 Aug 2008 00:12:15 +0200 diff -r 250a286e47ec -r 12307bf68e06 packages/debian-sarge/python2.3-libxml2dom/debian/changelog --- a/packages/debian-sarge/python2.3-libxml2dom/debian/changelog Sat Aug 30 00:51:04 2008 +0200 +++ b/packages/debian-sarge/python2.3-libxml2dom/debian/changelog Sun Aug 31 01:31:31 2008 +0200 @@ -11,6 +11,7 @@ * Introduced support for validation, together with the libxml2dom.errors module. * Improved error messages related to parsing. + * Added DOMConfiguration support to documents. -- Paul Boddie Tue, 26 Aug 2008 00:12:33 +0200 diff -r 250a286e47ec -r 12307bf68e06 packages/ubuntu-feisty/python-libxml2dom/debian/changelog --- a/packages/ubuntu-feisty/python-libxml2dom/debian/changelog Sat Aug 30 00:51:04 2008 +0200 +++ b/packages/ubuntu-feisty/python-libxml2dom/debian/changelog Sun Aug 31 01:31:31 2008 +0200 @@ -11,6 +11,7 @@ * Introduced support for validation, together with the libxml2dom.errors module. * Improved error messages related to parsing. + * Added DOMConfiguration support to documents. -- Paul Boddie Tue, 26 Aug 2008 00:11:32 +0200 diff -r 250a286e47ec -r 12307bf68e06 packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog --- a/packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog Sat Aug 30 00:51:04 2008 +0200 +++ b/packages/ubuntu-hoary/python2.4-libxml2dom/debian/changelog Sun Aug 31 01:31:31 2008 +0200 @@ -11,6 +11,7 @@ * Introduced support for validation, together with the libxml2dom.errors module. * Improved error messages related to parsing. + * Added DOMConfiguration support to documents. -- Paul Boddie Tue, 26 Aug 2008 00:10:37 +0200 diff -r 250a286e47ec -r 12307bf68e06 tests/test_invalid_relaxng.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_invalid_relaxng.xml Sun Aug 31 01:31:31 2008 +0200 @@ -0,0 +1,10 @@ + + + + + + + + + + diff -r 250a286e47ec -r 12307bf68e06 tests/test_valid_relaxng.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_valid_relaxng.py Sun Aug 31 01:31:31 2008 +0200 @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +import libxml2dom + +schema = libxml2dom.parse("tests/test_valid_relaxng.xml") +d = libxml2dom.parse("tests/test_valid.xml") +print d.validate(schema) +print d.validateDocument(schema) +print d.getParameter("error-handler") + +schema = libxml2dom.parse("tests/test_invalid_relaxng.xml") +d = libxml2dom.parse("tests/test_invalid.xml") +print d.validate(schema) +print d.validateDocument(schema) +print d.getParameter("error-handler") + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 250a286e47ec -r 12307bf68e06 tests/test_valid_relaxng.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_valid_relaxng.xml Sun Aug 31 01:31:31 2008 +0200 @@ -0,0 +1,9 @@ + + + + + + + + +