summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/orcus/xmlcontext.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/orcus/xmlcontext.cxx')
-rw-r--r--sc/source/filter/orcus/xmlcontext.cxx292
1 files changed, 292 insertions, 0 deletions
diff --git a/sc/source/filter/orcus/xmlcontext.cxx b/sc/source/filter/orcus/xmlcontext.cxx
new file mode 100644
index 000000000..94ef50159
--- /dev/null
+++ b/sc/source/filter/orcus/xmlcontext.cxx
@@ -0,0 +1,292 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <orcusfiltersimpl.hxx>
+#include <orcusinterface.hxx>
+#include <orcusxml.hxx>
+#include <document.hxx>
+#include <tokenarray.hxx>
+
+#include <vcl/weld.hxx>
+#include <ucbhelper/content.hxx>
+#include <sal/log.hxx>
+#include <osl/file.hxx>
+
+#include <orcus/xml_structure_tree.hpp>
+#include <orcus/xml_namespace.hpp>
+#include <orcus/orcus_xml.hpp>
+#include <orcus/sax_parser_base.hpp>
+#include <orcus/stream.hpp>
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <comphelper/processfactory.hxx>
+
+#include <string>
+#include <sstream>
+
+namespace com::sun::star::ucb { class XCommandEnvironment; }
+
+#define BUFFER_SIZE 4096
+
+using namespace com::sun::star;
+
+namespace {
+
+ScOrcusXMLTreeParam::EntryData& setUserDataToEntry(weld::TreeView& rControl,
+ const weld::TreeIter& rEntry, ScOrcusXMLTreeParam::UserDataStoreType& rStore, ScOrcusXMLTreeParam::EntryType eType)
+{
+ rStore.push_back(std::make_unique<ScOrcusXMLTreeParam::EntryData>(eType));
+ rControl.set_id(rEntry, weld::toId(rStore.back().get()));
+ return *rStore.back();
+}
+
+void setEntityNameToUserData(
+ ScOrcusXMLTreeParam::EntryData& rEntryData,
+ const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
+{
+ rEntryData.mnNamespaceID = walker.get_xmlns_index(entity.ns);
+}
+
+OUString toString(const orcus::xml_structure_tree::entity_name& entity, const orcus::xml_structure_tree::walker& walker)
+{
+ OUStringBuffer aBuf;
+ if (entity.ns)
+ {
+ // Namespace exists. Use the short version of the xml namespace name for display.
+ std::string aShortName = walker.get_xmlns_short_name(entity.ns);
+ aBuf.appendAscii(aShortName.c_str());
+ aBuf.append(':');
+ }
+ aBuf.append(OUString(entity.name.data(), entity.name.size(), RTL_TEXTENCODING_UTF8));
+ return aBuf.makeStringAndClear();
+}
+
+void populateTree(
+ weld::TreeView& rTreeCtrl, orcus::xml_structure_tree::walker& rWalker,
+ const orcus::xml_structure_tree::entity_name& rElemName, bool bRepeat,
+ const weld::TreeIter* pParent, ScOrcusXMLTreeParam& rParam)
+{
+ OUString sEntry(toString(rElemName, rWalker));
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeCtrl.make_iterator());
+ rTreeCtrl.insert(pParent, -1, &sEntry, nullptr, nullptr, nullptr, false, xEntry.get());
+ rTreeCtrl.set_image(*xEntry, rParam.maImgElementDefault, -1);
+
+ ScOrcusXMLTreeParam::EntryData& rEntryData = setUserDataToEntry(rTreeCtrl,
+ *xEntry, rParam.m_UserDataStore,
+ bRepeat ? ScOrcusXMLTreeParam::ElementRepeat : ScOrcusXMLTreeParam::ElementDefault);
+
+ setEntityNameToUserData(rEntryData, rElemName, rWalker);
+
+ if (bRepeat)
+ {
+ // Recurring elements use different icon.
+ rTreeCtrl.set_image(*xEntry, rParam.maImgElementRepeat, -1);
+ }
+
+ orcus::xml_structure_tree::entity_names_type aNames = rWalker.get_attributes();
+
+ // Insert attributes.
+ for (const orcus::xml_structure_tree::entity_name& rAttrName : aNames)
+ {
+ OUString sAttr(toString(rAttrName, rWalker));
+ std::unique_ptr<weld::TreeIter> xAttr(rTreeCtrl.make_iterator());
+ rTreeCtrl.insert(xEntry.get(), -1, &sAttr, nullptr, nullptr, nullptr, false, xAttr.get());
+
+ ScOrcusXMLTreeParam::EntryData& rAttrData =
+ setUserDataToEntry(rTreeCtrl, *xAttr, rParam.m_UserDataStore, ScOrcusXMLTreeParam::Attribute);
+ setEntityNameToUserData(rAttrData, rAttrName, rWalker);
+
+ rTreeCtrl.set_image(*xAttr, rParam.maImgAttribute, -1);
+ }
+
+ aNames = rWalker.get_children();
+
+ // Non-leaf if it has child elements, leaf otherwise.
+ rEntryData.mbLeafNode = aNames.empty();
+
+ // Insert child elements recursively.
+ for (const auto& rName : aNames)
+ {
+ orcus::xml_structure_tree::element aElem = rWalker.descend(rName);
+ populateTree(rTreeCtrl, rWalker, rName, aElem.repeat, xEntry.get(), rParam);
+ rWalker.ascend();
+ }
+}
+
+class TreeUpdateSwitch
+{
+ weld::TreeView& mrTreeCtrl;
+public:
+ explicit TreeUpdateSwitch(weld::TreeView& rTreeCtrl) : mrTreeCtrl(rTreeCtrl)
+ {
+ mrTreeCtrl.freeze();
+ }
+
+ ~TreeUpdateSwitch()
+ {
+ mrTreeCtrl.thaw();
+ }
+};
+
+void loadContentFromURL(const OUString& rURL, std::string& rStrm)
+{
+ ucbhelper::Content aContent(
+ rURL, uno::Reference<ucb::XCommandEnvironment>(), comphelper::getProcessComponentContext());
+ uno::Reference<io::XInputStream> xStrm = aContent.openStream();
+
+ std::ostringstream aStrmBuf;
+ uno::Sequence<sal_Int8> aBytes;
+ size_t nBytesRead = 0;
+ do
+ {
+ nBytesRead = xStrm->readBytes(aBytes, BUFFER_SIZE);
+ const sal_Int8* p = aBytes.getConstArray();
+ aStrmBuf << std::string(p, p + nBytesRead);
+ }
+ while (nBytesRead == BUFFER_SIZE);
+
+ rStrm = aStrmBuf.str();
+}
+
+}
+
+ScOrcusXMLContextImpl::ScOrcusXMLContextImpl(ScDocument& rDoc, const OUString& rPath) :
+ ScOrcusXMLContext(), mrDoc(rDoc), maPath(rPath) {}
+
+ScOrcusXMLContextImpl::~ScOrcusXMLContextImpl() {}
+
+void ScOrcusXMLContextImpl::loadXMLStructure(weld::TreeView& rTreeCtrl, ScOrcusXMLTreeParam& rParam)
+{
+ rParam.m_UserDataStore.clear();
+
+ std::string aStrm;
+ loadContentFromURL(maPath, aStrm);
+
+ if (aStrm.empty())
+ return;
+
+ orcus::xmlns_context cxt = maNsRepo.create_context();
+ orcus::xml_structure_tree aXmlTree(cxt);
+ try
+ {
+ aXmlTree.parse(aStrm);
+
+ TreeUpdateSwitch aSwitch(rTreeCtrl);
+ rTreeCtrl.clear();
+
+ orcus::xml_structure_tree::walker aWalker = aXmlTree.get_walker();
+
+ // Root element.
+ orcus::xml_structure_tree::element aElem = aWalker.root();
+ populateTree(rTreeCtrl, aWalker, aElem.name, aElem.repeat, nullptr, rParam);
+ }
+ catch (const orcus::sax::malformed_xml_error& e)
+ {
+ SAL_WARN("sc.orcus", "Malformed XML error: " << e.what());
+ }
+ catch (const std::exception& e)
+ {
+ SAL_WARN("sc.orcus", "parsing failed with an unknown error " << e.what());
+ }
+
+ rTreeCtrl.all_foreach([&rTreeCtrl](weld::TreeIter& rEntry){
+ rTreeCtrl.expand_row(rEntry);
+ return false;
+ });
+}
+
+namespace {
+
+class SetNamespaceAlias
+{
+ orcus::orcus_xml& mrFilter;
+ orcus::xmlns_repository& mrNsRepo;
+public:
+ SetNamespaceAlias(orcus::orcus_xml& filter, orcus::xmlns_repository& repo) :
+ mrFilter(filter), mrNsRepo(repo) {}
+
+ void operator() (size_t index)
+ {
+ orcus::xmlns_id_t nsid = mrNsRepo.get_identifier(index);
+ if (nsid == orcus::XMLNS_UNKNOWN_ID)
+ return;
+
+ std::string alias = mrNsRepo.get_short_name(index);
+ mrFilter.set_namespace_alias(alias.c_str(), nsid);
+ }
+};
+
+}
+
+void ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam)
+{
+ ScOrcusFactory aFactory(mrDoc, true);
+
+ OUString aSysPath;
+ if (osl::FileBase::getSystemPathFromFileURL(maPath, aSysPath) != osl::FileBase::E_None)
+ return;
+
+ OString aOSysPath = OUStringToOString(aSysPath, RTL_TEXTENCODING_UTF8);
+ const char* path = aOSysPath.getStr();
+
+ try
+ {
+ orcus::orcus_xml filter(maNsRepo, &aFactory, nullptr);
+
+ // Define all used namespaces.
+ std::for_each(rParam.maNamespaces.begin(), rParam.maNamespaces.end(), SetNamespaceAlias(filter, maNsRepo));
+
+ // Set cell links.
+ for (const ScOrcusImportXMLParam::CellLink& rLink : rParam.maCellLinks)
+ {
+ OUString aTabName;
+ mrDoc.GetName(rLink.maPos.Tab(), aTabName);
+ filter.set_cell_link(
+ rLink.maPath.getStr(),
+ OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
+ rLink.maPos.Row(), rLink.maPos.Col());
+ }
+
+ // Set range links.
+ for (const ScOrcusImportXMLParam::RangeLink& rLink : rParam.maRangeLinks)
+ {
+ OUString aTabName;
+ mrDoc.GetName(rLink.maPos.Tab(), aTabName);
+ filter.start_range(
+ OUStringToOString(aTabName, RTL_TEXTENCODING_UTF8).getStr(),
+ rLink.maPos.Row(), rLink.maPos.Col());
+
+ std::for_each(rLink.maFieldPaths.begin(), rLink.maFieldPaths.end(),
+ [&filter](const OString& rFieldPath)
+ {
+ filter.append_field_link(rFieldPath, std::string_view());
+ }
+ );
+
+ std::for_each(rLink.maRowGroups.begin(), rLink.maRowGroups.end(),
+ [&filter] (const OString& rRowGroup)
+ {
+ filter.set_range_row_group(rRowGroup);
+ }
+ );
+
+ filter.commit_range();
+ }
+
+ orcus::file_content content(path);
+ filter.read_stream(content.str());
+
+ aFactory.finalize();
+ }
+ catch (const std::exception&)
+ {
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */