Skip to content

Commit 04c8718

Browse files
author
Steve Canny
committed
add CT_Relationship element class
1 parent 81e047e commit 04c8718

3 files changed

Lines changed: 157 additions & 0 deletions

File tree

opc/oxml.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@
1414

1515
from lxml import etree, objectify
1616

17+
from opc.constants import NAMESPACE as NS, RELATIONSHIP_TARGET_MODE as RTM
18+
1719

1820
# configure objectified XML parser
1921
fallback_lookup = objectify.ObjectifyElementClassLookup()
2022
element_class_lookup = etree.ElementNamespaceClassLookup(fallback_lookup)
2123
oxml_parser = etree.XMLParser(remove_blank_text=True)
2224
oxml_parser.set_element_class_lookup(element_class_lookup)
2325

26+
nsmap = {
27+
'ct': NS.OPC_CONTENT_TYPES,
28+
'pr': NS.OPC_RELATIONSHIPS,
29+
}
30+
2431

2532
# ===========================================================================
2633
# functions
@@ -29,3 +36,74 @@
2936
def oxml_fromstring(text):
3037
"""``etree.fromstring()`` replacement that uses oxml parser"""
3138
return objectify.fromstring(text, oxml_parser)
39+
40+
41+
def oxml_tostring(elm, encoding=None, pretty_print=False, standalone=None):
42+
# if xsi parameter is not set to False, PowerPoint won't load without a
43+
# repair step; deannotate removes some original xsi:type tags in core.xml
44+
# if this parameter is left out (or set to True)
45+
objectify.deannotate(elm, xsi=False, cleanup_namespaces=True)
46+
return etree.tostring(elm, encoding=encoding, pretty_print=pretty_print,
47+
standalone=standalone)
48+
49+
50+
# ===========================================================================
51+
# Custom element classes
52+
# ===========================================================================
53+
54+
class OxmlBaseElement(objectify.ObjectifiedElement):
55+
"""
56+
Base class for all custom element classes, to add standardized behavior
57+
to all classes in one place.
58+
"""
59+
@property
60+
def xml(self):
61+
"""
62+
Return XML string for this element, suitable for testing purposes.
63+
Pretty printed for readability and without an XML declaration at the
64+
top.
65+
"""
66+
return oxml_tostring(self, encoding='unicode', pretty_print=True)
67+
68+
69+
class CT_Relationship(OxmlBaseElement):
70+
"""
71+
``<Relationship>`` element, representing a single relationship from a
72+
source to a target part.
73+
"""
74+
@property
75+
def rId(self):
76+
"""
77+
String held in the ``Id`` attribute of this ``<Relationship>``
78+
element.
79+
"""
80+
return self.get('Id')
81+
82+
@property
83+
def reltype(self):
84+
"""
85+
String held in the ``Type`` attribute of this ``<Relationship>``
86+
element.
87+
"""
88+
return self.get('Type')
89+
90+
@property
91+
def target_ref(self):
92+
"""
93+
String held in the ``Target`` attribute of this ``<Relationship>``
94+
element.
95+
"""
96+
return self.get('Target')
97+
98+
@property
99+
def target_mode(self):
100+
"""
101+
String held in the ``TargetMode`` attribute of this
102+
``<Relationship>`` element, either ``Internal`` or ``External``.
103+
Defaults to ``Internal``.
104+
"""
105+
return self.get('TargetMode', RTM.INTERNAL)
106+
107+
108+
pr_namespace = element_class_lookup.get_namespace(nsmap['pr'])
109+
pr_namespace['Relationship'] = CT_Relationship

tests/test_oxml.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# test_oxml.py
4+
#
5+
# Copyright (C) 2013 Steve Canny scanny@cisco.com
6+
#
7+
# This module is part of python-pptx and is released under the MIT License:
8+
# http://www.opensource.org/licenses/mit-license.php
9+
10+
"""Test suite for opc.oxml module."""
11+
12+
from opc.constants import RELATIONSHIP_TARGET_MODE as RTM
13+
14+
from .unitdata import a_Relationship
15+
16+
17+
class DescribeCT_Relationship(object):
18+
19+
def it_provides_read_access_to_xml_values(self):
20+
rel = a_Relationship().element
21+
assert rel.rId == 'rId9'
22+
assert rel.reltype == 'ReLtYpE'
23+
assert rel.target_ref == 'docProps/core.xml'
24+
assert rel.target_mode == RTM.INTERNAL

tests/unitdata.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# unitdata.py
4+
#
5+
# Copyright (C) 2013 Steve Canny scanny@cisco.com
6+
#
7+
# This module is part of python-pptx and is released under the MIT License:
8+
# http://www.opensource.org/licenses/mit-license.php
9+
10+
"""Test data builders for unit tests"""
11+
12+
from opc.constants import NAMESPACE as NS
13+
from opc.oxml import oxml_fromstring
14+
15+
16+
class BaseBuilder(object):
17+
"""
18+
Provides common behavior for all data builders.
19+
"""
20+
@property
21+
def element(self):
22+
"""Return element based on XML generated by builder"""
23+
return oxml_fromstring(self.xml)
24+
25+
26+
class CT_RelationshipBuilder(BaseBuilder):
27+
"""
28+
Test data builder for CT_Relationship (Relationship) XML element that
29+
appears in .rels files
30+
"""
31+
def __init__(self):
32+
"""Establish instance variables with default values"""
33+
self._rId = 'rId9'
34+
self._reltype = 'ReLtYpE'
35+
self._target = 'docProps/core.xml'
36+
self._target_mode = None
37+
self._namespace = ' xmlns="%s"' % NS.OPC_RELATIONSHIPS
38+
39+
@property
40+
def target_mode(self):
41+
if self._target_mode is None:
42+
return ''
43+
return ' TargetMode="%s"' % self._target_mode
44+
45+
@property
46+
def xml(self):
47+
"""Return Relationship element"""
48+
tmpl = '<Relationship%s Id="%s" Type="%s" Target="%s"%s/>\n'
49+
return tmpl % (self._namespace, self._rId, self._reltype,
50+
self._target, self.target_mode)
51+
52+
53+
def a_Relationship():
54+
"""Return a CT_RelationshipBuilder instance"""
55+
return CT_RelationshipBuilder()

0 commit comments

Comments
 (0)