1# Copyright (c) 2010-2024 openpyxl
2
3
4from openpyxl.descriptors.serialisable import Serialisable
5from openpyxl.descriptors import (
6 Typed,
7 String,
8 Bool,
9 Integer,
10 NoneSet,
11 Sequence,
12)
13from openpyxl.descriptors.excel import Relation
14from openpyxl.descriptors.nested import NestedText
15from openpyxl.descriptors.sequence import NestedSequence, ValueSequence
16
17from openpyxl.packaging.relationship import (
18 Relationship,
19 get_rels_path,
20 get_dependents
21 )
22from openpyxl.xml.constants import SHEET_MAIN_NS
23from openpyxl.xml.functions import fromstring
24
25
26"""Manage links to external Workbooks"""
27
28
29class ExternalCell(Serialisable):
30
31 r = String()
32 t = NoneSet(values=(['b', 'd', 'n', 'e', 's', 'str', 'inlineStr']))
33 vm = Integer(allow_none=True)
34 v = NestedText(allow_none=True, expected_type=str)
35
36 def __init__(self,
37 r=None,
38 t=None,
39 vm=None,
40 v=None,
41 ):
42 self.r = r
43 self.t = t
44 self.vm = vm
45 self.v = v
46
47
48class ExternalRow(Serialisable):
49
50 r = Integer()
51 cell = Sequence(expected_type=ExternalCell)
52
53 __elements__ = ('cell',)
54
55 def __init__(self,
56 r=(),
57 cell=None,
58 ):
59 self.r = r
60 self.cell = cell
61
62
63class ExternalSheetData(Serialisable):
64
65 sheetId = Integer()
66 refreshError = Bool(allow_none=True)
67 row = Sequence(expected_type=ExternalRow)
68
69 __elements__ = ('row',)
70
71 def __init__(self,
72 sheetId=None,
73 refreshError=None,
74 row=(),
75 ):
76 self.sheetId = sheetId
77 self.refreshError = refreshError
78 self.row = row
79
80
81class ExternalSheetDataSet(Serialisable):
82
83 sheetData = Sequence(expected_type=ExternalSheetData, )
84
85 __elements__ = ('sheetData',)
86
87 def __init__(self,
88 sheetData=None,
89 ):
90 self.sheetData = sheetData
91
92
93class ExternalSheetNames(Serialisable):
94
95 sheetName = ValueSequence(expected_type=str)
96
97 __elements__ = ('sheetName',)
98
99 def __init__(self,
100 sheetName=(),
101 ):
102 self.sheetName = sheetName
103
104
105class ExternalDefinedName(Serialisable):
106
107 tagname = "definedName"
108
109 name = String()
110 refersTo = String(allow_none=True)
111 sheetId = Integer(allow_none=True)
112
113 def __init__(self,
114 name=None,
115 refersTo=None,
116 sheetId=None,
117 ):
118 self.name = name
119 self.refersTo = refersTo
120 self.sheetId = sheetId
121
122
123class ExternalBook(Serialisable):
124
125 tagname = "externalBook"
126
127 sheetNames = Typed(expected_type=ExternalSheetNames, allow_none=True)
128 definedNames = NestedSequence(expected_type=ExternalDefinedName)
129 sheetDataSet = Typed(expected_type=ExternalSheetDataSet, allow_none=True)
130 id = Relation()
131
132 __elements__ = ('sheetNames', 'definedNames', 'sheetDataSet')
133
134 def __init__(self,
135 sheetNames=None,
136 definedNames=(),
137 sheetDataSet=None,
138 id=None,
139 ):
140 self.sheetNames = sheetNames
141 self.definedNames = definedNames
142 self.sheetDataSet = sheetDataSet
143 self.id = id
144
145
146class ExternalLink(Serialisable):
147
148 tagname = "externalLink"
149
150 _id = None
151 _path = "/xl/externalLinks/externalLink{0}.xml"
152 _rel_type = "externalLink"
153 mime_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml"
154
155 externalBook = Typed(expected_type=ExternalBook, allow_none=True)
156 file_link = Typed(expected_type=Relationship, allow_none=True) # link to external file
157
158 __elements__ = ('externalBook', )
159
160 def __init__(self,
161 externalBook=None,
162 ddeLink=None,
163 oleLink=None,
164 extLst=None,
165 ):
166 self.externalBook = externalBook
167 # ignore other items for the moment.
168
169
170 def to_tree(self):
171 node = super().to_tree()
172 node.set("xmlns", SHEET_MAIN_NS)
173 return node
174
175
176 @property
177 def path(self):
178 return self._path.format(self._id)
179
180
181def read_external_link(archive, book_path):
182 src = archive.read(book_path)
183 node = fromstring(src)
184 book = ExternalLink.from_tree(node)
185
186 link_path = get_rels_path(book_path)
187 deps = get_dependents(archive, link_path)
188 book.file_link = deps[0]
189
190 return book