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 : #include "ucbhelper/content.hxx"
18 :
19 : #include <orcus/spreadsheet/import_interface.hpp>
20 : #include <orcus/xml_structure_tree.hpp>
21 : #include <orcus/xml_namespace.hpp>
22 : #include <orcus/orcus_xml.hpp>
23 : #include <orcus/global.hpp>
24 :
25 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
26 :
27 : #include <string>
28 : #include <sstream>
29 :
30 : #define BUFFER_SIZE 4096
31 :
32 : using namespace com::sun::star;
33 :
34 : namespace {
35 :
36 0 : ScOrcusXMLTreeParam::EntryData& setUserDataToEntry(
37 : SvTreeListEntry& rEntry, ScOrcusXMLTreeParam::UserDataStoreType& rStore, ScOrcusXMLTreeParam::EntryType eType)
38 : {
39 0 : rStore.push_back(new ScOrcusXMLTreeParam::EntryData(eType));
40 0 : rEntry.SetUserData(&rStore.back());
41 0 : return rStore.back();
42 : }
43 :
44 0 : void setEntityNameToUserData(
45 : ScOrcusXMLTreeParam::EntryData& rEntryData,
46 : const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
47 : {
48 0 : rEntryData.mnNamespaceID = walker.get_xmlns_index(entity.ns);
49 0 : }
50 :
51 0 : OUString toString(const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
52 : {
53 0 : OUStringBuffer aBuf;
54 0 : if (entity.ns)
55 : {
56 : // Namespace exists. Use the short version of the xml namespace name for display.
57 0 : std::string aShortName = walker.get_xmlns_short_name(entity.ns);
58 0 : aBuf.appendAscii(aShortName.c_str());
59 0 : aBuf.append(':');
60 : }
61 0 : aBuf.append(OUString(entity.name.get(), entity.name.size(), RTL_TEXTENCODING_UTF8));
62 0 : return aBuf.makeStringAndClear();
63 : }
64 :
65 0 : void populateTree(
66 : SvTreeListBox& rTreeCtrl, orcus::xml_structure_tree::walker& rWalker,
67 : const orcus::xml_structure_tree::entity_name& rElemName, bool bRepeat,
68 : SvTreeListEntry* pParent, ScOrcusXMLTreeParam& rParam)
69 : {
70 0 : SvTreeListEntry* pEntry = rTreeCtrl.InsertEntry(toString(rElemName, rWalker), pParent);
71 0 : if (!pEntry)
72 : // Can this ever happen!?
73 0 : return;
74 :
75 : ScOrcusXMLTreeParam::EntryData& rEntryData = setUserDataToEntry(
76 : *pEntry, rParam.maUserDataStore,
77 0 : bRepeat ? ScOrcusXMLTreeParam::ElementRepeat : ScOrcusXMLTreeParam::ElementDefault);
78 :
79 0 : setEntityNameToUserData(rEntryData, rElemName, rWalker);
80 :
81 0 : if (bRepeat)
82 : {
83 : // Recurring elements use different icon.
84 0 : rTreeCtrl.SetExpandedEntryBmp(pEntry, rParam.maImgElementRepeat);
85 0 : rTreeCtrl.SetCollapsedEntryBmp(pEntry, rParam.maImgElementRepeat);
86 : }
87 :
88 0 : if (pParent)
89 0 : rTreeCtrl.Expand(pParent);
90 :
91 0 : orcus::xml_structure_tree::entity_names_type aNames;
92 :
93 : // Insert attributes.
94 0 : rWalker.get_attributes(aNames);
95 0 : orcus::xml_structure_tree::entity_names_type::const_iterator it = aNames.begin();
96 0 : orcus::xml_structure_tree::entity_names_type::const_iterator itEnd = aNames.end();
97 0 : for (; it != itEnd; ++it)
98 : {
99 0 : const orcus::xml_structure_tree::entity_name& rAttrName = *it;
100 0 : SvTreeListEntry* pAttr = rTreeCtrl.InsertEntry(toString(rAttrName, rWalker), pEntry);
101 :
102 0 : if (!pAttr)
103 0 : continue;
104 :
105 : ScOrcusXMLTreeParam::EntryData& rAttrData =
106 0 : setUserDataToEntry(*pAttr, rParam.maUserDataStore, ScOrcusXMLTreeParam::Attribute);
107 0 : setEntityNameToUserData(rAttrData, rAttrName, rWalker);
108 :
109 0 : rTreeCtrl.SetExpandedEntryBmp(pAttr, rParam.maImgAttribute);
110 0 : rTreeCtrl.SetCollapsedEntryBmp(pAttr, rParam.maImgAttribute);
111 : }
112 0 : rTreeCtrl.Expand(pEntry);
113 :
114 0 : rWalker.get_children(aNames);
115 :
116 : // Non-leaf if it has child elements, leaf otherwise.
117 0 : rEntryData.mbLeafNode = aNames.empty();
118 :
119 : // Insert child elements recursively.
120 0 : for (it = aNames.begin(), itEnd = aNames.end(); it != itEnd; ++it)
121 : {
122 0 : orcus::xml_structure_tree::element aElem = rWalker.descend(*it);
123 0 : populateTree(rTreeCtrl, rWalker, *it, aElem.repeat, pEntry, rParam);
124 0 : rWalker.ascend();
125 0 : }
126 : }
127 :
128 : class TreeUpdateSwitch
129 : {
130 : SvTreeListBox& mrTreeCtrl;
131 : public:
132 0 : TreeUpdateSwitch(SvTreeListBox& rTreeCtrl) : mrTreeCtrl(rTreeCtrl)
133 : {
134 0 : mrTreeCtrl.SetUpdateMode(false);
135 0 : }
136 :
137 0 : ~TreeUpdateSwitch()
138 : {
139 0 : mrTreeCtrl.SetUpdateMode(true);
140 0 : }
141 : };
142 :
143 : class InsertFieldPath : std::unary_function<OString, void>
144 : {
145 : orcus::orcus_xml& mrFilter;
146 : public:
147 0 : InsertFieldPath(orcus::orcus_xml& rFilter) : mrFilter(rFilter) {}
148 0 : void operator() (const OString& rPath)
149 : {
150 0 : mrFilter.append_field_link(rPath.getStr());
151 0 : }
152 : };
153 :
154 0 : void loadContentFromURL(const OUString& rURL, std::string& rStrm)
155 : {
156 : ucbhelper::Content aContent(
157 0 : rURL, uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
158 0 : uno::Reference<io::XInputStream> xStrm = aContent.openStream();
159 :
160 0 : std::ostringstream aStrmBuf;
161 0 : uno::Sequence<sal_Int8> aBytes;
162 0 : size_t nBytesRead = 0;
163 0 : do
164 : {
165 0 : nBytesRead = xStrm->readBytes(aBytes, BUFFER_SIZE);
166 0 : const sal_Int8* p = aBytes.getConstArray();
167 0 : aStrmBuf << std::string(p, p + nBytesRead);
168 : }
169 : while (nBytesRead == BUFFER_SIZE);
170 :
171 0 : rStrm = aStrmBuf.str();
172 0 : }
173 :
174 : }
175 :
176 0 : ScOrcusXMLContextImpl::ScOrcusXMLContextImpl(ScDocument& rDoc, const OUString& rPath) :
177 0 : ScOrcusXMLContext(), mrDoc(rDoc), maPath(rPath) {}
178 :
179 0 : ScOrcusXMLContextImpl::~ScOrcusXMLContextImpl() {}
180 :
181 0 : bool ScOrcusXMLContextImpl::loadXMLStructure(SvTreeListBox& rTreeCtrl, ScOrcusXMLTreeParam& rParam)
182 : {
183 0 : rParam.maUserDataStore.clear();
184 :
185 0 : std::string aStrm;
186 0 : loadContentFromURL(maPath, aStrm);
187 :
188 0 : if (aStrm.empty())
189 0 : return false;
190 :
191 0 : orcus::xmlns_context cxt = maNsRepo.create_context();
192 0 : orcus::xml_structure_tree aXmlTree(cxt);
193 : try
194 : {
195 0 : aXmlTree.parse(&aStrm[0], aStrm.size());
196 :
197 0 : TreeUpdateSwitch aSwitch(rTreeCtrl);
198 0 : rTreeCtrl.Clear();
199 0 : rTreeCtrl.SetDefaultCollapsedEntryBmp(rParam.maImgElementDefault);
200 0 : rTreeCtrl.SetDefaultExpandedEntryBmp(rParam.maImgElementDefault);
201 :
202 0 : orcus::xml_structure_tree::walker aWalker = aXmlTree.get_walker();
203 :
204 : // Root element.
205 0 : orcus::xml_structure_tree::element aElem = aWalker.root();
206 0 : populateTree(rTreeCtrl, aWalker, aElem.name, aElem.repeat, NULL, rParam);
207 : }
208 0 : catch (const std::exception&)
209 : {
210 : // Parsing of this XML file failed.
211 0 : return false;
212 : }
213 :
214 0 : return true;
215 : }
216 :
217 : namespace {
218 :
219 : class SetNamespaceAlias : std::unary_function<size_t, void>
220 : {
221 : orcus::orcus_xml& mrFilter;
222 : orcus::xmlns_repository& mrNsRepo;
223 : public:
224 0 : SetNamespaceAlias(orcus::orcus_xml& filter, orcus::xmlns_repository& repo) :
225 0 : mrFilter(filter), mrNsRepo(repo) {}
226 :
227 0 : void operator() (size_t index)
228 : {
229 0 : orcus::xmlns_id_t nsid = mrNsRepo.get_identifier(index);
230 0 : if (nsid == orcus::XMLNS_UNKNOWN_ID)
231 0 : return;
232 :
233 0 : std::string alias = mrNsRepo.get_short_name(index);
234 0 : mrFilter.set_namespace_alias(alias.c_str(), nsid);
235 : }
236 : };
237 :
238 :
239 : }
240 :
241 0 : bool ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam)
242 : {
243 0 : ScOrcusFactory aFactory(mrDoc);
244 0 : OString aSysPath = ScOrcusFiltersImpl::toSystemPath(maPath);
245 0 : const char* path = aSysPath.getStr();
246 : try
247 : {
248 0 : orcus::orcus_xml filter(maNsRepo, &aFactory, NULL);
249 :
250 : // Define all used namespaces.
251 0 : std::for_each(rParam.maNamespaces.begin(), rParam.maNamespaces.end(), SetNamespaceAlias(filter, maNsRepo));
252 :
253 : {
254 : // Set cell links.
255 0 : ScOrcusImportXMLParam::CellLinksType::const_iterator it = rParam.maCellLinks.begin();
256 0 : ScOrcusImportXMLParam::CellLinksType::const_iterator itEnd = rParam.maCellLinks.end();
257 0 : for (; it != itEnd; ++it)
258 : {
259 0 : const ScOrcusImportXMLParam::CellLink& rLink = *it;
260 0 : OUString aTabName;
261 0 : mrDoc.GetName(rLink.maPos.Tab(), aTabName);
262 : filter.set_cell_link(
263 : rLink.maPath.getStr(),
264 : OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
265 0 : rLink.maPos.Row(), rLink.maPos.Col());
266 0 : }
267 : }
268 :
269 : {
270 : // Set range links.
271 0 : ScOrcusImportXMLParam::RangeLinksType::const_iterator it = rParam.maRangeLinks.begin();
272 0 : ScOrcusImportXMLParam::RangeLinksType::const_iterator itEnd = rParam.maRangeLinks.end();
273 0 : for (; it != itEnd; ++it)
274 : {
275 0 : const ScOrcusImportXMLParam::RangeLink& rLink = *it;
276 0 : OUString aTabName;
277 0 : mrDoc.GetName(rLink.maPos.Tab(), aTabName);
278 : filter.start_range(
279 : OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
280 0 : rLink.maPos.Row(), rLink.maPos.Col());
281 :
282 0 : std::for_each(rLink.maFieldPaths.begin(), rLink.maFieldPaths.end(), InsertFieldPath(filter));
283 :
284 0 : filter.commit_range();
285 0 : }
286 : }
287 :
288 0 : filter.read_file(path);
289 : }
290 0 : catch (const std::exception&)
291 : {
292 0 : return false;
293 : }
294 0 : return true;
295 : }
296 :
297 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|