Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include "orcusfiltersimpl.hxx"
11 : #include "orcusinterface.hxx"
12 : #include "orcusxml.hxx"
13 : #include "document.hxx"
14 :
15 : #include "svtools/treelistbox.hxx"
16 : #include "svtools/treelistentry.hxx"
17 :
18 : #include <orcus/spreadsheet/import_interface.hpp>
19 : #include <orcus/xml_structure_tree.hpp>
20 : #include <orcus/xml_namespace.hpp>
21 : #include <orcus/orcus_xml.hpp>
22 : #include <orcus/global.hpp>
23 :
24 : #include <string>
25 :
26 : namespace {
27 :
28 0 : ScOrcusXMLTreeParam::EntryData& setUserDataToEntry(
29 : SvTreeListEntry& rEntry, ScOrcusXMLTreeParam::UserDataStoreType& rStore, ScOrcusXMLTreeParam::EntryType eType)
30 : {
31 0 : rStore.push_back(new ScOrcusXMLTreeParam::EntryData(eType));
32 0 : rEntry.SetUserData(&rStore.back());
33 0 : return rStore.back();
34 : }
35 :
36 0 : void setEntityNameToUserData(
37 : ScOrcusXMLTreeParam::EntryData& rEntryData,
38 : const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
39 : {
40 0 : rEntryData.mnNamespaceID = walker.get_xmlns_index(entity.ns);
41 0 : }
42 :
43 0 : OUString toString(const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
44 : {
45 0 : OUStringBuffer aBuf;
46 0 : if (entity.ns)
47 : {
48 : // Namespace exists. Use the short version of the xml namespace name for display.
49 0 : std::string aShortName = walker.get_xmlns_short_name(entity.ns);
50 0 : aBuf.appendAscii(aShortName.c_str());
51 0 : aBuf.append(':');
52 : }
53 0 : aBuf.append(OUString(entity.name.get(), entity.name.size(), RTL_TEXTENCODING_UTF8));
54 0 : return aBuf.makeStringAndClear();
55 : }
56 :
57 0 : void populateTree(
58 : SvTreeListBox& rTreeCtrl, orcus::xml_structure_tree::walker& rWalker,
59 : const orcus::xml_structure_tree::entity_name& rElemName, bool bRepeat,
60 : SvTreeListEntry* pParent, ScOrcusXMLTreeParam& rParam)
61 : {
62 0 : SvTreeListEntry* pEntry = rTreeCtrl.InsertEntry(toString(rElemName, rWalker), pParent);
63 0 : if (!pEntry)
64 : // Can this ever happen!?
65 0 : return;
66 :
67 : ScOrcusXMLTreeParam::EntryData& rEntryData = setUserDataToEntry(
68 : *pEntry, rParam.maUserDataStore,
69 0 : bRepeat ? ScOrcusXMLTreeParam::ElementRepeat : ScOrcusXMLTreeParam::ElementDefault);
70 :
71 0 : setEntityNameToUserData(rEntryData, rElemName, rWalker);
72 :
73 0 : if (bRepeat)
74 : {
75 : // Recurring elements use different icon.
76 0 : rTreeCtrl.SetExpandedEntryBmp(pEntry, rParam.maImgElementRepeat);
77 0 : rTreeCtrl.SetCollapsedEntryBmp(pEntry, rParam.maImgElementRepeat);
78 : }
79 :
80 0 : if (pParent)
81 0 : rTreeCtrl.Expand(pParent);
82 :
83 0 : orcus::xml_structure_tree::entity_names_type aNames;
84 :
85 : // Insert attributes.
86 0 : rWalker.get_attributes(aNames);
87 0 : orcus::xml_structure_tree::entity_names_type::const_iterator it = aNames.begin();
88 0 : orcus::xml_structure_tree::entity_names_type::const_iterator itEnd = aNames.end();
89 0 : for (; it != itEnd; ++it)
90 : {
91 0 : const orcus::xml_structure_tree::entity_name& rAttrName = *it;
92 0 : SvTreeListEntry* pAttr = rTreeCtrl.InsertEntry(toString(rAttrName, rWalker), pEntry);
93 :
94 0 : if (!pAttr)
95 0 : continue;
96 :
97 : ScOrcusXMLTreeParam::EntryData& rAttrData =
98 0 : setUserDataToEntry(*pAttr, rParam.maUserDataStore, ScOrcusXMLTreeParam::Attribute);
99 0 : setEntityNameToUserData(rAttrData, rAttrName, rWalker);
100 :
101 0 : rTreeCtrl.SetExpandedEntryBmp(pAttr, rParam.maImgAttribute);
102 0 : rTreeCtrl.SetCollapsedEntryBmp(pAttr, rParam.maImgAttribute);
103 : }
104 0 : rTreeCtrl.Expand(pEntry);
105 :
106 0 : rWalker.get_children(aNames);
107 :
108 : // Non-leaf if it has child elements, leaf otherwise.
109 0 : rEntryData.mbLeafNode = aNames.empty();
110 :
111 : // Insert child elements recursively.
112 0 : for (it = aNames.begin(), itEnd = aNames.end(); it != itEnd; ++it)
113 : {
114 0 : orcus::xml_structure_tree::element aElem = rWalker.descend(*it);
115 0 : populateTree(rTreeCtrl, rWalker, *it, aElem.repeat, pEntry, rParam);
116 0 : rWalker.ascend();
117 0 : }
118 : }
119 :
120 : class TreeUpdateSwitch
121 : {
122 : SvTreeListBox& mrTreeCtrl;
123 : public:
124 0 : TreeUpdateSwitch(SvTreeListBox& rTreeCtrl) : mrTreeCtrl(rTreeCtrl)
125 : {
126 0 : mrTreeCtrl.SetUpdateMode(false);
127 0 : }
128 :
129 0 : ~TreeUpdateSwitch()
130 : {
131 0 : mrTreeCtrl.SetUpdateMode(true);
132 0 : }
133 : };
134 :
135 : class InsertFieldPath : std::unary_function<OString, void>
136 : {
137 : orcus::orcus_xml& mrFilter;
138 : public:
139 0 : InsertFieldPath(orcus::orcus_xml& rFilter) : mrFilter(rFilter) {}
140 0 : void operator() (const OString& rPath)
141 : {
142 0 : mrFilter.append_field_link(rPath.getStr());
143 0 : }
144 : };
145 :
146 : }
147 :
148 0 : ScOrcusXMLContextImpl::ScOrcusXMLContextImpl(ScDocument& rDoc, const OUString& rPath) :
149 0 : ScOrcusXMLContext(), mrDoc(rDoc), maPath(rPath) {}
150 :
151 0 : ScOrcusXMLContextImpl::~ScOrcusXMLContextImpl() {}
152 :
153 0 : bool ScOrcusXMLContextImpl::loadXMLStructure(SvTreeListBox& rTreeCtrl, ScOrcusXMLTreeParam& rParam)
154 : {
155 0 : rParam.maUserDataStore.clear();
156 :
157 0 : OString aSysPath = ScOrcusFiltersImpl::toSystemPath(maPath);
158 0 : const char* path = aSysPath.getStr();
159 :
160 : // TODO: Use our own stream loading call instead of one from orcus.
161 0 : std::string aStrm;
162 0 : orcus::load_file_content(path, aStrm);
163 :
164 0 : if (aStrm.empty())
165 0 : return false;
166 :
167 0 : orcus::xmlns_context cxt = maNsRepo.create_context();
168 0 : orcus::xml_structure_tree aXmlTree(cxt);
169 : try
170 : {
171 0 : aXmlTree.parse(&aStrm[0], aStrm.size());
172 :
173 0 : TreeUpdateSwitch aSwitch(rTreeCtrl);
174 0 : rTreeCtrl.Clear();
175 0 : rTreeCtrl.SetDefaultCollapsedEntryBmp(rParam.maImgElementDefault);
176 0 : rTreeCtrl.SetDefaultExpandedEntryBmp(rParam.maImgElementDefault);
177 :
178 0 : orcus::xml_structure_tree::walker aWalker = aXmlTree.get_walker();
179 :
180 : // Root element.
181 0 : orcus::xml_structure_tree::element aElem = aWalker.root();
182 0 : populateTree(rTreeCtrl, aWalker, aElem.name, aElem.repeat, NULL, rParam);
183 : }
184 0 : catch (const std::exception&)
185 : {
186 : // Parsing of this XML file failed.
187 0 : return false;
188 : }
189 :
190 0 : return true;
191 : }
192 :
193 : namespace {
194 :
195 : class SetNamespaceAlias : std::unary_function<size_t, void>
196 : {
197 : orcus::orcus_xml& mrFilter;
198 : orcus::xmlns_repository& mrNsRepo;
199 : public:
200 0 : SetNamespaceAlias(orcus::orcus_xml& filter, orcus::xmlns_repository& repo) :
201 0 : mrFilter(filter), mrNsRepo(repo) {}
202 :
203 0 : void operator() (size_t index)
204 : {
205 0 : orcus::xmlns_id_t nsid = mrNsRepo.get_identifier(index);
206 0 : if (nsid == orcus::XMLNS_UNKNOWN_ID)
207 0 : return;
208 :
209 0 : std::string alias = mrNsRepo.get_short_name(index);
210 0 : mrFilter.set_namespace_alias(alias.c_str(), nsid);
211 : }
212 : };
213 :
214 :
215 : }
216 :
217 0 : bool ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam)
218 : {
219 0 : ScOrcusFactory aFactory(mrDoc);
220 0 : OString aSysPath = ScOrcusFiltersImpl::toSystemPath(maPath);
221 0 : const char* path = aSysPath.getStr();
222 : try
223 : {
224 0 : orcus::orcus_xml filter(maNsRepo, &aFactory, NULL);
225 :
226 : // Define all used namespaces.
227 0 : std::for_each(rParam.maNamespaces.begin(), rParam.maNamespaces.end(), SetNamespaceAlias(filter, maNsRepo));
228 :
229 : {
230 : // Set cell links.
231 0 : ScOrcusImportXMLParam::CellLinksType::const_iterator it = rParam.maCellLinks.begin();
232 0 : ScOrcusImportXMLParam::CellLinksType::const_iterator itEnd = rParam.maCellLinks.end();
233 0 : for (; it != itEnd; ++it)
234 : {
235 0 : const ScOrcusImportXMLParam::CellLink& rLink = *it;
236 0 : OUString aTabName;
237 0 : mrDoc.GetName(rLink.maPos.Tab(), aTabName);
238 : filter.set_cell_link(
239 : rLink.maPath.getStr(),
240 : rtl::OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
241 0 : rLink.maPos.Row(), rLink.maPos.Col());
242 0 : }
243 : }
244 :
245 : {
246 : // Set range links.
247 0 : ScOrcusImportXMLParam::RangeLinksType::const_iterator it = rParam.maRangeLinks.begin();
248 0 : ScOrcusImportXMLParam::RangeLinksType::const_iterator itEnd = rParam.maRangeLinks.end();
249 0 : for (; it != itEnd; ++it)
250 : {
251 0 : const ScOrcusImportXMLParam::RangeLink& rLink = *it;
252 0 : OUString aTabName;
253 0 : mrDoc.GetName(rLink.maPos.Tab(), aTabName);
254 : filter.start_range(
255 : rtl::OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
256 0 : rLink.maPos.Row(), rLink.maPos.Col());
257 :
258 0 : std::for_each(rLink.maFieldPaths.begin(), rLink.maFieldPaths.end(), InsertFieldPath(filter));
259 :
260 0 : filter.commit_range();
261 0 : }
262 : }
263 :
264 0 : filter.read_file(path);
265 : }
266 0 : catch (const std::exception&)
267 : {
268 0 : return false;
269 : }
270 0 : return true;
271 : }
272 :
273 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|