LibreOffice Module sc (master) 1
xmlcontext.cxx
Go to the documentation of this file.
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#include <tokenarray.hxx>
15
16#include <utility>
17#include <vcl/weld.hxx>
18#include <ucbhelper/content.hxx>
19#include <sal/log.hxx>
20#include <osl/file.hxx>
21
22#include <orcus/xml_structure_tree.hpp>
23#include <orcus/xml_namespace.hpp>
24#include <orcus/orcus_xml.hpp>
25#include <orcus/sax_parser_base.hpp>
26#include <orcus/stream.hpp>
27
28#include <com/sun/star/io/XInputStream.hpp>
30
31#include <string>
32#include <sstream>
33
34namespace com::sun::star::ucb { class XCommandEnvironment; }
35
36#define BUFFER_SIZE 4096
37
38using namespace com::sun::star;
39
40namespace {
41
42ScOrcusXMLTreeParam::EntryData& setUserDataToEntry(weld::TreeView& rControl,
44{
45 rStore.push_back(std::make_unique<ScOrcusXMLTreeParam::EntryData>(eType));
46 rControl.set_id(rEntry, weld::toId(rStore.back().get()));
47 return *rStore.back();
48}
49
50void setEntityNameToUserData(
52 const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
53{
54 rEntryData.mnNamespaceID = walker.get_xmlns_index(entity.ns);
55}
56
57OUString toString(const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
58{
59 OUStringBuffer aBuf;
60 if (entity.ns)
61 {
62 // Namespace exists. Use the short version of the xml namespace name for display.
63 std::string aShortName = walker.get_xmlns_short_name(entity.ns);
64 aBuf.appendAscii(aShortName.c_str());
65 aBuf.append(':');
66 }
67 aBuf.append(OUString(entity.name.data(), entity.name.size(), RTL_TEXTENCODING_UTF8));
68 return aBuf.makeStringAndClear();
69}
70
71void populateTree(
72 weld::TreeView& rTreeCtrl, orcus::xml_structure_tree::walker& rWalker,
73 const orcus::xml_structure_tree::entity_name& rElemName, bool bRepeat,
74 const weld::TreeIter* pParent, ScOrcusXMLTreeParam& rParam)
75{
76 OUString sEntry(toString(rElemName, rWalker));
77 std::unique_ptr<weld::TreeIter> xEntry(rTreeCtrl.make_iterator());
78 rTreeCtrl.insert(pParent, -1, &sEntry, nullptr, nullptr, nullptr, false, xEntry.get());
79 rTreeCtrl.set_image(*xEntry, rParam.maImgElementDefault, -1);
80
81 ScOrcusXMLTreeParam::EntryData& rEntryData = setUserDataToEntry(rTreeCtrl,
82 *xEntry, rParam.m_UserDataStore,
84
85 setEntityNameToUserData(rEntryData, rElemName, rWalker);
86
87 if (bRepeat)
88 {
89 // Recurring elements use different icon.
90 rTreeCtrl.set_image(*xEntry, rParam.maImgElementRepeat, -1);
91 }
92
93 orcus::xml_structure_tree::entity_names_type aNames = rWalker.get_attributes();
94
95 // Insert attributes.
96 for (const orcus::xml_structure_tree::entity_name& rAttrName : aNames)
97 {
98 OUString sAttr(toString(rAttrName, rWalker));
99 std::unique_ptr<weld::TreeIter> xAttr(rTreeCtrl.make_iterator());
100 rTreeCtrl.insert(xEntry.get(), -1, &sAttr, nullptr, nullptr, nullptr, false, xAttr.get());
101
103 setUserDataToEntry(rTreeCtrl, *xAttr, rParam.m_UserDataStore, ScOrcusXMLTreeParam::Attribute);
104 setEntityNameToUserData(rAttrData, rAttrName, rWalker);
105
106 rTreeCtrl.set_image(*xAttr, rParam.maImgAttribute, -1);
107 }
108
109 aNames = rWalker.get_children();
110
111 // Non-leaf if it has child elements, leaf otherwise.
112 rEntryData.mbLeafNode = aNames.empty();
113
114 // Insert child elements recursively.
115 for (const auto& rName : aNames)
116 {
117 orcus::xml_structure_tree::element aElem = rWalker.descend(rName);
118 populateTree(rTreeCtrl, rWalker, rName, aElem.repeat, xEntry.get(), rParam);
119 rWalker.ascend();
120 }
121}
122
123class TreeUpdateSwitch
124{
125 weld::TreeView& mrTreeCtrl;
126public:
127 explicit TreeUpdateSwitch(weld::TreeView& rTreeCtrl) : mrTreeCtrl(rTreeCtrl)
128 {
129 mrTreeCtrl.freeze();
130 }
131
132 ~TreeUpdateSwitch()
133 {
134 mrTreeCtrl.thaw();
135 }
136};
137
138void loadContentFromURL(const OUString& rURL, std::string& rStrm)
139{
140 ucbhelper::Content aContent(
141 rURL, uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
142 uno::Reference<io::XInputStream> xStrm = aContent.openStream();
143
144 std::ostringstream aStrmBuf;
145 uno::Sequence<sal_Int8> aBytes;
146 size_t nBytesRead = 0;
147 do
148 {
149 nBytesRead = xStrm->readBytes(aBytes, BUFFER_SIZE);
150 const sal_Int8* p = aBytes.getConstArray();
151 aStrmBuf << std::string(p, p + nBytesRead);
152 }
153 while (nBytesRead == BUFFER_SIZE);
154
155 rStrm = aStrmBuf.str();
156}
157
158}
159
161 ScOrcusXMLContext(), mrDoc(rDoc), maPath(std::move(aPath)) {}
162
164
166{
167 rParam.m_UserDataStore.clear();
168
169 std::string aStrm;
170 loadContentFromURL(maPath, aStrm);
171
172 if (aStrm.empty())
173 return;
174
175 orcus::xmlns_context cxt = maNsRepo.create_context();
176 orcus::xml_structure_tree aXmlTree(cxt);
177 try
178 {
179 aXmlTree.parse(aStrm);
180
181 TreeUpdateSwitch aSwitch(rTreeCtrl);
182 rTreeCtrl.clear();
183
184 orcus::xml_structure_tree::walker aWalker = aXmlTree.get_walker();
185
186 // Root element.
187 orcus::xml_structure_tree::element aElem = aWalker.root();
188 populateTree(rTreeCtrl, aWalker, aElem.name, aElem.repeat, nullptr, rParam);
189 }
190 catch (const orcus::sax::malformed_xml_error& e)
191 {
192 SAL_WARN("sc.orcus", "Malformed XML error: " << e.what());
193 }
194 catch (const std::exception& e)
195 {
196 SAL_WARN("sc.orcus", "parsing failed with an unknown error " << e.what());
197 }
198
199 rTreeCtrl.all_foreach([&rTreeCtrl](weld::TreeIter& rEntry){
200 rTreeCtrl.expand_row(rEntry);
201 return false;
202 });
203}
204
205namespace {
206
207class SetNamespaceAlias
208{
209 orcus::orcus_xml& mrFilter;
210 orcus::xmlns_repository& mrNsRepo;
211public:
212 SetNamespaceAlias(orcus::orcus_xml& filter, orcus::xmlns_repository& repo) :
213 mrFilter(filter), mrNsRepo(repo) {}
214
215 void operator() (size_t index)
216 {
217 orcus::xmlns_id_t nsid = mrNsRepo.get_identifier(index);
218 if (nsid == orcus::XMLNS_UNKNOWN_ID)
219 return;
220
221 std::string alias = mrNsRepo.get_short_name(index);
222 mrFilter.set_namespace_alias(alias.c_str(), nsid);
223 }
224};
225
226}
227
229{
230 ScOrcusFactory aFactory(mrDoc, true);
231
232 OUString aSysPath;
233 if (osl::FileBase::getSystemPathFromFileURL(maPath, aSysPath) != osl::FileBase::E_None)
234 return;
235
236 OString aOSysPath = OUStringToOString(aSysPath, RTL_TEXTENCODING_UTF8);
237 const char* path = aOSysPath.getStr();
238
239 try
240 {
241 orcus::orcus_xml filter(maNsRepo, &aFactory, nullptr);
242
243 // Define all used namespaces.
244 std::for_each(rParam.maNamespaces.begin(), rParam.maNamespaces.end(), SetNamespaceAlias(filter, maNsRepo));
245
246 // Set cell links.
247 for (const ScOrcusImportXMLParam::CellLink& rLink : rParam.maCellLinks)
248 {
249 OUString aTabName;
250 mrDoc.GetName(rLink.maPos.Tab(), aTabName);
251 filter.set_cell_link(
252 rLink.maPath.getStr(),
253 OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
254 rLink.maPos.Row(), rLink.maPos.Col());
255 }
256
257 // Set range links.
258 for (const ScOrcusImportXMLParam::RangeLink& rLink : rParam.maRangeLinks)
259 {
260 OUString aTabName;
261 mrDoc.GetName(rLink.maPos.Tab(), aTabName);
262 filter.start_range(
263 OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
264 rLink.maPos.Row(), rLink.maPos.Col());
265
266 std::for_each(rLink.maFieldPaths.begin(), rLink.maFieldPaths.end(),
267 [&filter](const OString& rFieldPath)
268 {
269 filter.append_field_link(rFieldPath, std::string_view());
270 }
271 );
272
273 std::for_each(rLink.maRowGroups.begin(), rLink.maRowGroups.end(),
274 [&filter] (const OString& rRowGroup)
275 {
276 filter.set_range_row_group(rRowGroup);
277 }
278 );
279
280 filter.commit_range();
281 }
282
283 orcus::file_content content(path);
284 filter.read_stream(content.str());
285
286 aFactory.finalize();
287 }
288 catch (const std::exception&)
289 {
290 }
291}
292
293/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Any maPath
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:216
virtual void finalize() override
Definition: interface.cxx:407
virtual void importXML(const ScOrcusImportXMLParam &rParam) override
Definition: xmlcontext.cxx:228
virtual void loadXMLStructure(weld::TreeView &rTreeCtrl, ScOrcusXMLTreeParam &rParam) override
Definition: xmlcontext.cxx:165
ScOrcusXMLContextImpl(ScDocument &rDoc, OUString aPath)
XML namespace repository for this context.
Definition: xmlcontext.cxx:160
virtual ~ScOrcusXMLContextImpl() override
Definition: xmlcontext.cxx:163
orcus::xmlns_repository maNsRepo
css::uno::Reference< css::io::XInputStream > openStream()
virtual std::unique_ptr< TreeIter > make_iterator(const TreeIter *pOrig=nullptr) const=0
virtual void expand_row(const TreeIter &rIter)=0
virtual void insert(const TreeIter *pParent, int pos, const OUString *pStr, const OUString *pId, const OUString *pIconName, VirtualDevice *pImageSurface, bool bChildrenOnDemand, TreeIter *pRet)=0
virtual void clear()=0
virtual void set_image(int row, const OUString &rImage, int col=-1)=0
virtual void set_id(int row, const OUString &rId)=0
virtual void all_foreach(const std::function< bool(TreeIter &)> &func)=0
virtual void freeze()=0
virtual void thaw()=0
DocumentType eType
void * p
#define SAL_WARN(area, stream)
aBuf
Reference< XComponentContext > getProcessComponentContext()
void SvStream & rStrm
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString toString(OptionInfo const *info)
OUString toId(const void *pValue)
const PowerPointImport & mrFilter
std::vector< RangeLink > maRangeLinks
Definition: orcusxml.hxx:76
std::vector< CellLink > maCellLinks
Definition: orcusxml.hxx:75
std::vector< size_t > maNamespaces
Definition: orcusxml.hxx:74
Custom data stored with each tree item.
Definition: orcusxml.hxx:32
Parameter used during call to ScOrcusFilters::loadXMLStructure().
Definition: orcusxml.hxx:27
UserDataStoreType m_UserDataStore
Store all custom data instances since the tree control doesn't manage the life cycle of user data.
Definition: orcusxml.hxx:52
std::vector< std::unique_ptr< EntryData > > UserDataStoreType
Definition: orcusxml.hxx:42
OUString maImgElementRepeat
Definition: orcusxml.hxx:45
OUString maImgAttribute
Definition: orcusxml.hxx:46
OUString maImgElementDefault
Definition: orcusxml.hxx:44
signed char sal_Int8
#define BUFFER_SIZE
Definition: xmlcontext.cxx:36