pxdom

pxdom 1.2
A Python DOM implementation

pxdom is a W3C DOM Level 3 implementation for XML 1.0/1.1 with/without namespaces, using Python and OMG-style (_get/_set) bindings. All features described in the Core and LS Recommendations are supported, with the following exceptions:

pxdom runs on Python 1.5.2 or later, but certain features are dependent on Python version:

Installation

Copy pxdom.py into any folder in your Python path, for example /usr/lib/python/site-packages or C:\Python23\Lib\site-packages.

pxdom can also be included and imported as a submodule of another package. This is a good strategy if you wish to distribute a DOM-based application without having to worry about the versions of Python and/or PyXML installed on users’ machines; the only dependencies are the standard library string-handling and URL-related modules.

Usage

The pxdom module implements the DOMImplementationSource interface from DOM Level 3 Core. So to parse a document from a file, use eg.:

import pxdom
dom= pxdom.getDOMImplementation('')
parser= dom.createLSParser(dom.MODE_SYNCHRONOUS, None)
doc= parser.parseURI('file:///f|/data/doc.xml')

For more on using DOM Level 3 Load features to create documents from various sources, see the DOM Level 3 LS specification.

Alternatively, the pxdom module offers the convenience functions parse and parseString, which work like the Python minidom module’s functions of the same names:

doc= pxdom.parse('F:\\data\\doc.xml')
doc= pxdom.parseString('<el attr="val">content</el>')

DOMConfiguration parameters

The result of the parse operation depends on the parameters set on the LSParser.domConfig mapping. By default, in accordance with the DOM specification, all CDATA sections will be replaced with plain text nodes and all bound entity references will be replaced by the contents of the entity referred to. This includes external entity references and the external subset.

If you use the parse and parseString functions, pxdom will set the parameter ‘cdata-sections’ to True, allowing CDATA sections to stay in the document, and the parameter ‘pxdom-resolve-resources’ to False so external entities and the external subset are left alone. This is to emulate the behaviour of the Python standard library’s minidom module.

If you prefer also to receive EntityReference nodes in your document, set the ‘entities’ parameter to a true value. For example:

parser= dom.createLSParser(dom.MODE_SYNCHRONOUS, None)
parser.domConfig.setParameter('cdata-sections', 1)
parser.domConfig.setParameter('entities', 1)
doc= parser.parseURI('file:///home/data/doc.xml')

Or, using the parse/parseString shortcut functions, you can pass in an optional dictionary of extra DOMConfiguration parameters to set, like:

doc= pxdom.parse('file:///home/data/doc.xml', {'entities': 1})

(Of course, this usage would no longer be minidom-compatible.) See the DOM 3 Core and LS specifications for more DOMConfiguration parameters.

Extensions

pxdom supports some supplemental non-standard features. Their names are always prefixed with ‘pxdom’ to avoid confusion with the standard.

Extra DOMConfiguration parameters

Configuration parameters in DOM Level 3 may affect parsing, serialisation and normalisation operations. pxdom adds a few new parameters not defined in the specification.

If you want to set a pxdom extra parameter to a non-default value but still be compatible with any other DOM Level 3 implementation, you can use the DOMConfiguration.canSetParameter method to ensure that the parameter is supported first.

pxdom-resolve-resources

Applies to: parsing. Default: True (except with parse/parseString functions).

Dictates whether resources external to the document file will be resolved and used. This affects external entities and the DTD external subset.

pxdom uses only the SYSTEM identifier in fetching an external resource, so parsing an XHTML document, for example, would make many requests to the W3C server to grab the document type information. This is quite slow. Note also that at the time of writing the DTD referenced by XHTML 1.1 documents has acknowledged bugs in it, which pxdom is unable to parse. (This has been corrected for the forthcoming XHTML Modularization Second Edition specification.)

To do something with PUBLIC identifiers, such as supply local copies of DTDs, you would have to provide a standard DOM LSResourceResolver object to the configuration parameter ‘resource-resolver’. Resource resolvers will never be called if ‘pxdom-resolve-resources’ is set to false.

When the convenience functions parse and parseString are called, ‘pxdom-resolve-resources’ will be false by default, instead of true, for minidom compatibility.

pxdom-normalize-text

Applies to: normalisation. Default: True.

Dictates whether text node normalisation (as performed by the DOM Level 1 Core Node.normalize method) will take place when the DOM Level 3 Core Document.normalizeDocument method is called.

By default, matching the DOM specification, text node normalisation does occur, but pxdom allows this to be turned off if unwanted.

pxdom-update-entities

Applies to: normalisation. Default: True.

Dictates whether entity reference nodes have their content child nodes updated from the declaration stored in the doctype. This may result in descendants with different namespaces when the entity reference has been moved, if the entity contains prefixes whose namespaces are not declared in the entity.

By default, matching the DOM specification, entities are updated, but pxdom allows this to be turned off if unwanted.

pxdom-reset-identity

Applies to: normalisation. Default: True.

Dictates whether attributes should have their user-specified-IDness (as set by the setAttributeId etc. methods) reset to false during document normalisation.

By default, matching the DOM specification, this does occur, but pxdom allows this to be turned off if unwanted.

pxdom-preserve-base-uri

Applies to: parsing, normalisation, serialisation. Default: True.

When enabled, pxdom attempts to preserve the base URI context whenever a node that changes base URI is replaced by its contents. This can happen when an element with an xml:base attribute is SKIPped by a DOM 3 LS filter, or when an entity reference with a different base URI to its parent is flattened.

By default, matching the DOM specification, base URIs are preserved. However, the extra xml:base attributes added to child elements may be unwanted if you are working with entities (especially external entities) but do not wish to use XML Base, so pxdom allows it to be turned off. If you do so, the DOMError warning ‘pi-base-uri-lost’ will also not be generated.

pxdom-assume-element-content

Applies to: parsing, normalisation, serialisation, isElementContentWhitespace. Default: False.

In order to support the feature Text.isElementContentWhitespace, pxdom must know the content model of the particular element that contains the text node. Often this is only defined in the DTD external subset, which might have been omitted or not read.

Normally, following the XML Information Set specification, pxdom will guess that elements with unknown content models do not contain ‘element content’ — so Text.isElementContentWhitespace will always return False for elements not mentioned in the DOCTYPE internal subset.

However, if the DOMConfiguration parameter ‘pxdom-assume-element-content’ is True, it will guess that unknown elements do contain element content, and so whitespace nodes inside them will be ‘element content whitespace’ (often referred to as ‘ignorable whitespace’).

This parameter can be combined with the ‘element-content-whitespace’ parameter to parse an XML file and return a DOM tree containing no superfluous whitespace nodes whatsoever, which can make subsequent processing much simpler:

parser= dom.createLSParser(dom.MODE_SYNCHRONOUS, None)
parser.domConfig.setParameter('element-content-whitespace', 0)
parser.domConfig.setParameter('pxdom-assume-element-content', 1)
doc= parser.parse('file:///data/foo.xml')

Extra object properties

Node.pxdomLocation

Read-only property giving a DOM Level 3 DOMLocator object for any Node. If the Node was created by a parsing operation this will reveal the file and row/column number in which the node was found - particularly useful for error-reporting purposes.

Node.pxdomContent

A convenience property to get the markup for a node, or replace the node with alternative parsed markup, without having to create a separate LSSerializer or LSParser.

All nodes have a readable pxdomContent, but only those at content level are writable (attribute nodes, for instance, are not). The document’s domConfig is used to give parameters for parse and serialise operations invoked by pxdomContent.

pxdomContent is an extended replacement for the ElementLS.markupContent property that was in earlier Working Drafts of the DOM 3 LS spec.

Entity.pxdomAvailable

A flag indicating whether the entity’s replacement content is available in the childNodes property. Internal entities are always available; unparsed external entities never are; for parsed external entities it depends on whether external resources were resolved at parse-time.

Entity.pxdomDocumentURI

On external entities, gives the actual URI the entity was read from, after applying the systemId to the baseURI and going through any LSResourceResolver redirection. For internal and unavailable entities this property is null.

DocumentType.pxdomElements/Attlists

In addition to entities and notations, pxdom includes NamedNodeMaps in the DocumentType for the other two types of declaration that might occur in the DTD. They can be read to get more information on content models than the DOM Level 3 TypeInfo interface makes available.

Extra pxdom node types

ElementDeclaration

ElementDeclarations can be obtained from the DocumentType.pxdomElements map. Its nodeName is the element name given in the corresponding DTD <!ELEMENT> declaration).

ElementDeclaration nodes have an integer contentType property with enum keys EMPTY_CONTENT, ANY_CONTENT, MIXED_CONTENT and ELEMENT_CONTENT. In the case of mixed and element content, the elements property gives more information on the child elements allowed.

AttributeDeclarationList

AttributeDeclarationLists can be obtained from the DocumentType.pxdomAttlists map. Its nodeName is the name of the element whose attributes it is defining, as given in the <!ATTLIST> declaration).

AttributeListDeclarations hold a NamedNodeMap in their declarations property, mapping attribute names from the declaration to corresponding AttributeDeclaration nodes.

AttributeDeclaration

AttributeDeclaration nodes have an integer attributeType property with enum keys ID_ATTR, IDREF_ATTR, IDREFS_ATTR, ENTITY_ATTR, ENTITIES_ATTR, NMTOKEN_ATTR, NMTOKENS_ATTR, NOTATION_ATTR, CDATA_ATTR and ENUMERATION_ATTR.

In the case of enumeration and notation attribute types, the typeValues property holds a list of possible string values. There is also an integer defaultType property with enum keys REQUIRED_VALUE, IMPLIED_VALUE, DEFAULT_VALUE and FIXED_VALUE. In the case of fixed and defaulting attributes, the childNodes property holds any text and/or entity reference nodes that make up the default value.

Changelog

Updates from 1.1 to 1.2

Updates from 1.0 to 1.1

Updates from 0.9 to 1.0

Updates from 0.8 to 0.9

Updates from 0.7 to 0.8

Updates from 0.6 to 0.7

Future work

Additional thanks to all responsible for the DOM Test Suite (which has caught many gotchas in previous pxdom versions, regardless of the bugs I keep filing against it), particularly Curt Arnold (for fixing many of them).

Licence (new-BSD-style)

Copyright © 2004, Andrew Clover. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

This software is provided by the copyright holder and contributors “as is” and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.