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 <vcl/weld.hxx>
17 #include <ucbhelper/content.hxx>
18 #include <sal/log.hxx>
19 #include <osl/file.hxx>
20 
21 #include <orcus/xml_structure_tree.hpp>
22 #include <orcus/xml_namespace.hpp>
23 #include <orcus/orcus_xml.hpp>
24 #include <orcus/sax_parser_base.hpp>
25 #include <orcus/stream.hpp>
26 
27 #include <com/sun/star/io/XInputStream.hpp>
29 
30 #include <string>
31 #include <sstream>
32 
33 namespace com::sun::star::ucb { class XCommandEnvironment; }
34 
35 #define BUFFER_SIZE 4096
36 
37 using namespace com::sun::star;
38 
39 namespace {
40 
41 ScOrcusXMLTreeParam::EntryData& setUserDataToEntry(weld::TreeView& rControl,
43 {
44  rStore.push_back(std::make_unique<ScOrcusXMLTreeParam::EntryData>(eType));
45  rControl.set_id(rEntry, OUString::number(reinterpret_cast<sal_Int64>(rStore.back().get())));
46  return *rStore.back();
47 }
48 
49 void setEntityNameToUserData(
51  const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
52 {
53  rEntryData.mnNamespaceID = walker.get_xmlns_index(entity.ns);
54 }
55 
56 OUString toString(const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
57 {
58  OUStringBuffer aBuf;
59  if (entity.ns)
60  {
61  // Namespace exists. Use the short version of the xml namespace name for display.
62  std::string aShortName = walker.get_xmlns_short_name(entity.ns);
63  aBuf.appendAscii(aShortName.c_str());
64  aBuf.append(':');
65  }
66  aBuf.append(OUString(entity.name.get(), entity.name.size(), RTL_TEXTENCODING_UTF8));
67  return aBuf.makeStringAndClear();
68 }
69 
70 void populateTree(
71  weld::TreeView& rTreeCtrl, orcus::xml_structure_tree::walker& rWalker,
72  const orcus::xml_structure_tree::entity_name& rElemName, bool bRepeat,
73  const weld::TreeIter* pParent, ScOrcusXMLTreeParam& rParam)
74 {
75  OUString sEntry(toString(rElemName, rWalker));
76  std::unique_ptr<weld::TreeIter> xEntry(rTreeCtrl.make_iterator());
77  rTreeCtrl.insert(pParent, -1, &sEntry, nullptr, nullptr, nullptr, false, xEntry.get());
78  rTreeCtrl.set_image(*xEntry, rParam.maImgElementDefault, -1);
79 
80  ScOrcusXMLTreeParam::EntryData& rEntryData = setUserDataToEntry(rTreeCtrl,
81  *xEntry, rParam.m_UserDataStore,
83 
84  setEntityNameToUserData(rEntryData, rElemName, rWalker);
85 
86  if (bRepeat)
87  {
88  // Recurring elements use different icon.
89  rTreeCtrl.set_image(*xEntry, rParam.maImgElementRepeat, -1);
90  }
91 
92  orcus::xml_structure_tree::entity_names_type aNames;
93 
94  // Insert attributes.
95  rWalker.get_attributes(aNames);
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 
102  ScOrcusXMLTreeParam::EntryData& rAttrData =
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  rWalker.get_children(aNames);
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 
123 class TreeUpdateSwitch
124 {
125  weld::TreeView& mrTreeCtrl;
126 public:
127  explicit TreeUpdateSwitch(weld::TreeView& rTreeCtrl) : mrTreeCtrl(rTreeCtrl)
128  {
129  mrTreeCtrl.freeze();
130  }
131 
132  ~TreeUpdateSwitch()
133  {
134  mrTreeCtrl.thaw();
135  }
136 };
137 
138 void 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(rPath) {}
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[0], aStrm.size());
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 
205 namespace {
206 
207 class SetNamespaceAlias
208 {
209  orcus::orcus_xml& mrFilter;
210  orcus::xmlns_repository& mrNsRepo;
211 public:
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.getStr());
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.getStr());
277  }
278  );
279 
280  filter.commit_range();
281  }
282 
283  orcus::file_content content(path);
284  filter.read_stream(content.data(), content.size());
285 
286  aFactory.finalize();
287  }
288  catch (const std::exception&)
289  {
290  }
291 }
292 
293 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString maImgElementRepeat
Definition: orcusxml.hxx:46
Any maPath
virtual ~ScOrcusXMLContextImpl() override
Definition: xmlcontext.cxx:163
SCROW Row() const
Definition: address.hxx:262
virtual void insert(const TreeIter *pParent, int pos, const OUString *pStr, const OUString *pId, const OUString *pIconName, VirtualDevice *pImageSurface, bool bChildrenOnDemand, TreeIter *pRet)=0
signed char sal_Int8
OUString maImgAttribute
Definition: orcusxml.hxx:47
aBuf
virtual void clear()=0
virtual void finalize() override
Definition: interface.cxx:373
virtual void set_id(int row, const OUString &rId)=0
virtual std::unique_ptr< TreeIter > make_iterator(const TreeIter *pOrig=nullptr) const =0
virtual void thaw()=0
UserDataStoreType m_UserDataStore
Store all custom data instances since the tree control doesn't manage the life cycle of user data...
Definition: orcusxml.hxx:53
SCTAB Tab() const
Definition: address.hxx:271
std::vector< RangeLink > maRangeLinks
Definition: orcusxml.hxx:77
virtual void importXML(const ScOrcusImportXMLParam &rParam) override
Definition: xmlcontext.cxx:228
virtual void loadXMLStructure(weld::TreeView &rTreeCtrl, ScOrcusXMLTreeParam &rParam) override
Definition: xmlcontext.cxx:165
DocumentType eType
orcus::xmlns_repository maNsRepo
virtual void freeze()=0
#define BUFFER_SIZE
Definition: xmlcontext.cxx:35
virtual void expand_row(const TreeIter &rIter)=0
SCCOL Col() const
Definition: address.hxx:267
Parameter used during call to ScOrcusFilters::loadXMLStructure().
Definition: orcusxml.hxx:27
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
std::vector< size_t > maNamespaces
Definition: orcusxml.hxx:75
OUString maImgElementDefault
Definition: orcusxml.hxx:45
css::uno::Reference< css::io::XInputStream > openStream()
virtual void all_foreach(const std::function< bool(TreeIter &)> &func)=0
std::vector< CellLink > maCellLinks
Definition: orcusxml.hxx:76
void * p
Reference< XComponentContext > getProcessComponentContext()
std::vector< std::unique_ptr< EntryData > > UserDataStoreType
Definition: orcusxml.hxx:43
virtual void set_image(int row, const OUString &rImage, int col=-1)=0
#define SAL_WARN(area, stream)
const PowerPointImport & mrFilter
void SvStream & rStrm
Custom data stored with each tree item.
Definition: orcusxml.hxx:32
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:213
ScOrcusXMLContextImpl(ScDocument &rDoc, const OUString &rPath)
XML namespace repository for this context.
Definition: xmlcontext.cxx:160
OUString toString(OptionInfo const *info)