Skip to content

Commit 2cb9893

Browse files
author
Steve Canny
committed
oxml: add docx.oxml.base module
1 parent 946ab5e commit 2cb9893

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

docx/oxml/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# oxml/__init__.py
4+
#
5+
# Copyright (C) 2012, 2013 Steve Canny scanny@cisco.com
6+
#
7+
# This module is part of python-docx and is released under the MIT License:
8+
# http://www.opensource.org/licenses/mit-license.php
9+
10+
"""
11+
Initializes oxml sub-package, including registering custom element classes
12+
corresponding to Open XML elements.
13+
"""

docx/oxml/base.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# oxml/base.py
4+
#
5+
# Copyright (C) 2012, 2013 Steve Canny scanny@cisco.com
6+
#
7+
# This module is part of python-docx and is released under the MIT License:
8+
# http://www.opensource.org/licenses/mit-license.php
9+
10+
"""
11+
Common and utility code used by other modules in the docx.oxml subpackage.
12+
"""
13+
14+
from lxml import etree, objectify
15+
16+
17+
nsmap = {
18+
'w': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
19+
}
20+
21+
# configure objectified XML parser
22+
_fallback_lookup = objectify.ObjectifyElementClassLookup()
23+
element_class_lookup = etree.ElementNamespaceClassLookup(_fallback_lookup)
24+
oxml_parser = etree.XMLParser(remove_blank_text=True)
25+
oxml_parser.set_element_class_lookup(element_class_lookup)
26+
27+
28+
# ===========================================================================
29+
# utility functions
30+
# ===========================================================================
31+
32+
def _Element(tag, nsmap=None):
33+
return oxml_parser.makeelement(qn(tag), nsmap=nsmap)
34+
35+
36+
def nsdecls(*prefixes):
37+
return ' '.join(['xmlns:%s="%s"' % (pfx, nsmap[pfx]) for pfx in prefixes])
38+
39+
40+
def oxml_fromstring(text):
41+
"""``etree.fromstring()`` replacement that uses oxml parser"""
42+
return objectify.fromstring(text, oxml_parser)
43+
44+
45+
def oxml_tostring(elm, encoding=None, pretty_print=False, standalone=None):
46+
# if xsi parameter is not set to False, PowerPoint won't load without a
47+
# repair step; deannotate removes some original xsi:type tags in core.xml
48+
# if this parameter is left out (or set to True)
49+
objectify.deannotate(elm, xsi=False, cleanup_namespaces=False)
50+
# objectify.deannotate(elm, xsi=False, cleanup_namespaces=True)
51+
return etree.tostring(elm, encoding=encoding, pretty_print=pretty_print,
52+
standalone=standalone)
53+
54+
55+
def qn(tag):
56+
"""
57+
Stands for "qualified name", a utility function to turn a namespace
58+
prefixed tag name into a Clark-notation qualified tag name for lxml. For
59+
example, ``qn('p:cSld')`` returns ``'{http://schemas.../main}cSld'``.
60+
"""
61+
prefix, tagroot = tag.split(':')
62+
uri = nsmap[prefix]
63+
return '{%s}%s' % (uri, tagroot)
64+
65+
66+
def register_custom_element_class(tag, cls):
67+
"""
68+
Register *cls* to be constructed when the oxml parser encounters an
69+
element with matching *tag*. *tag* is a string of the form
70+
``nspfx:tagroot``, e.g. ``'w:document'``.
71+
"""
72+
nspfx, tagroot = tag.split(':')
73+
namespace = element_class_lookup.get_namespace(nsmap[nspfx])
74+
namespace[tagroot] = cls
75+
76+
77+
def _SubElement(parent, tag):
78+
return objectify.SubElement(parent, qn(tag), nsmap=nsmap)
79+
80+
81+
class OxmlBaseElement(objectify.ObjectifiedElement):
82+
"""
83+
Base class for all custom element classes, to add standardized behavior
84+
to all classes in one place.
85+
"""
86+
@property
87+
def xml(self):
88+
"""
89+
Return XML string for this element, suitable for testing purposes.
90+
Pretty printed for readability and without an XML declaration at the
91+
top.
92+
"""
93+
return oxml_tostring(self, encoding='unicode', pretty_print=True)

0 commit comments

Comments
 (0)