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::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
206{
207 ScOrcusFactory aFactory(mrDoc, true);
208
209 OUString aSysPath;
210 if (osl::FileBase::getSystemPathFromFileURL(maPath, aSysPath) != osl::FileBase::E_None)
211 return;
212
213 OString aOSysPath = OUStringToOString(aSysPath, RTL_TEXTENCODING_UTF8);
214 const char* path = aOSysPath.getStr();
215
216 try
217 {
218 orcus::orcus_xml filter(maNsRepo, &aFactory, nullptr);
219
220 // Define all used namespaces.
221 for (std::size_t index : rParam.maNamespaces)
222 {
223 orcus::xmlns_id_t nsid = maNsRepo.get_identifier(index);
224 if (nsid == orcus::XMLNS_UNKNOWN_ID)
225 continue;
226
227 std::ostringstream os;
228 os << "ns" << index;
229 std::string alias = os.str();
230 filter.set_namespace_alias(alias, nsid);
231 }
232
233 // Set cell links.
234 for (const ScOrcusImportXMLParam::CellLink& rLink : rParam.maCellLinks)
235 {
236 OUString aTabName;
237 mrDoc.GetName(rLink.maPos.Tab(), aTabName);
238 filter.set_cell_link(
239 rLink.maPath,
240 aTabName.toUtf8(),
241 rLink.maPos.Row(), rLink.maPos.Col());
242 }
243
244 // Set range links.
245 for (const ScOrcusImportXMLParam::RangeLink& rLink : rParam.maRangeLinks)
246 {
247 OUString aTabName;
248 mrDoc.GetName(rLink.maPos.Tab(), aTabName);
249 filter.start_range(
250 aTabName.toUtf8(),
251 rLink.maPos.Row(), rLink.maPos.Col());
252
253 std::for_each(rLink.maFieldPaths.begin(), rLink.maFieldPaths.end(),
254 [&filter](const OString& rFieldPath)
255 {
256 filter.append_field_link(rFieldPath, std::string_view());
257 }
258 );
259
260 std::for_each(rLink.maRowGroups.begin(), rLink.maRowGroups.end(),
261 [&filter] (const OString& rRowGroup)
262 {
263 filter.set_range_row_group(rRowGroup);
264 }
265 );
266
267 filter.commit_range();
268 }
269
270 orcus::file_content content(path);
271 filter.read_stream(content.str());
272
273 aFactory.finalize();
274 }
275 catch (const std::exception&)
276 {
277 }
278}
279
280/* 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:204
virtual void finalize() override
Definition: interface.cxx:427
virtual void importXML(const ScOrcusImportXMLParam &rParam) override
Definition: xmlcontext.cxx:205
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()
index
void SvStream & rStrm
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString toString(OptionInfo const *info)
OUString toId(const void *pValue)
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