diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-11-21 15:21:41 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-11-28 13:28:32 -0500 |
commit | 9d6ed5dd8ba3824ba0f1a9d179cfd9b2f8ba75b3 (patch) | |
tree | dd23779631b40ffca0f8becdda3223b484e9ee29 | |
parent | 3db55f9da3577653911c683091c72722288bc456 (diff) |
Correctly handle xml namespaces when importing xml content.
But it's still not working. I need to dig some more.
Change-Id: I06d4d70e1a4234b031741a496f2651d016c35ecc
-rw-r--r-- | sc/inc/orcusxml.hxx | 4 | ||||
-rw-r--r-- | sc/source/core/tool/orcusxml.cxx | 9 | ||||
-rw-r--r-- | sc/source/filter/orcus/xmlcontext.cxx | 54 | ||||
-rw-r--r-- | sc/source/ui/xmlsource/xmlsourcedlg.cxx | 31 |
4 files changed, 84 insertions, 14 deletions
diff --git a/sc/inc/orcusxml.hxx b/sc/inc/orcusxml.hxx index c3a981da3622..87be8a2b32c9 100644 --- a/sc/inc/orcusxml.hxx +++ b/sc/inc/orcusxml.hxx @@ -29,6 +29,7 @@ struct ScOrcusXMLTreeParam /** Custom data stored with each tree item. */ struct EntryData { + size_t mnNamespaceID; /// numerical ID for xml namespace EntryType meType; ScAddress maLinkedPos; /// linked cell position (invalid if unlinked) bool mbRangeParent:1; @@ -72,8 +73,11 @@ struct ScOrcusImportXMLParam typedef std::vector<CellLink> CellLinksType; typedef std::vector<RangeLink> RangeLinksType; + std::vector<size_t> maNamespaces; CellLinksType maCellLinks; RangeLinksType maRangeLinks; + + SC_DLLPUBLIC static rtl::OString getShortNamespaceName(size_t nIndex); }; #endif diff --git a/sc/source/core/tool/orcusxml.cxx b/sc/source/core/tool/orcusxml.cxx index 3f3c93c159e2..cef0333440d1 100644 --- a/sc/source/core/tool/orcusxml.cxx +++ b/sc/source/core/tool/orcusxml.cxx @@ -10,6 +10,7 @@ #include "orcusxml.hxx" #include "svtools/treelistbox.hxx" +#include "rtl/strbuf.hxx" ScOrcusXMLTreeParam::EntryData::EntryData(EntryType eType) : meType(eType), maLinkedPos(ScAddress::INITIALIZE_INVALID), mbRangeParent(false), mbLeafNode(true) {} @@ -27,4 +28,12 @@ const ScOrcusXMLTreeParam::EntryData* ScOrcusXMLTreeParam::getUserData(const SvT ScOrcusImportXMLParam::CellLink::CellLink(const ScAddress& rPos, const OString& rPath) : maPos(rPos), maPath(rPath) {} +OString ScOrcusImportXMLParam::getShortNamespaceName(size_t nIndex) +{ + OStringBuffer aBuf; + aBuf.append("ns"); + aBuf.append(static_cast<sal_Int32>(nIndex)); + return aBuf.makeStringAndClear(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/orcus/xmlcontext.cxx b/sc/source/filter/orcus/xmlcontext.cxx index 86865cd403f0..3ad6951227fc 100644 --- a/sc/source/filter/orcus/xmlcontext.cxx +++ b/sc/source/filter/orcus/xmlcontext.cxx @@ -31,6 +31,13 @@ ScOrcusXMLTreeParam::EntryData& setUserDataToEntry( 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; @@ -43,9 +50,10 @@ OUString toString(const orcus::xml_structure_tree::entity_name& entity, const or aBuf.append("???"); else { - aBuf.append("ns"); - aBuf.append(static_cast<sal_Int32>(index)); + OString aName = ScOrcusImportXMLParam::getShortNamespaceName(index); + aBuf.append(OUString(aName.getStr(), aName.getLength(), RTL_TEXTENCODING_UTF8)); } + aBuf.append(':'); } aBuf.append(OUString(entity.name.get(), entity.name.size(), RTL_TEXTENCODING_UTF8)); @@ -66,6 +74,8 @@ void populateTree( *pEntry, rParam.maUserDataStore, bRepeat ? ScOrcusXMLTreeParam::ElementRepeat : ScOrcusXMLTreeParam::ElementDefault); + setEntityNameToUserData(rEntryData, rElemName, rWalker); + if (bRepeat) { // Recurring elements use different icon. @@ -84,13 +94,16 @@ void populateTree( orcus::xml_structure_tree::entity_names_type::const_iterator itEnd = aNames.end(); for (; it != itEnd; ++it) { - orcus::xml_structure_tree::entity_name aAttrName = *it; - SvTreeListEntry* pAttr = rTreeCtrl.InsertEntry(toString(aAttrName, rWalker), pEntry); + const orcus::xml_structure_tree::entity_name& rAttrName = *it; + SvTreeListEntry* pAttr = rTreeCtrl.InsertEntry(toString(rAttrName, rWalker), pEntry); if (!pAttr) continue; - setUserDataToEntry(*pAttr, rParam.maUserDataStore, ScOrcusXMLTreeParam::Attribute); + ScOrcusXMLTreeParam::EntryData& rAttrData = + setUserDataToEntry(*pAttr, rParam.maUserDataStore, ScOrcusXMLTreeParam::Attribute); + setEntityNameToUserData(rAttrData, rAttrName, rWalker); + rTreeCtrl.SetExpandedEntryBmp(pAttr, rParam.maImgAttribute); rTreeCtrl.SetCollapsedEntryBmp(pAttr, rParam.maImgAttribute); } @@ -183,6 +196,30 @@ bool ScOrcusXMLContextImpl::loadXMLStructure(SvTreeListBox& rTreeCtrl, ScOrcusXM return true; } +namespace { + +class SetNamespaceAlias : std::unary_function<size_t, void> +{ + 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; + + OString aAlias = ScOrcusImportXMLParam::getShortNamespaceName(index); + mrFilter.set_namespace_alias(aAlias.getStr(), nsid); + } +}; + + +} + bool ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam) { ScOrcusFactory aFactory(mrDoc); @@ -192,8 +229,11 @@ bool ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam) { orcus::orcus_xml filter(maNsRepo, &aFactory, NULL); - // Set cell links. + // Define all used namespaces. + std::for_each(rParam.maNamespaces.begin(), rParam.maNamespaces.end(), SetNamespaceAlias(filter, maNsRepo)); + { + // Set cell links. ScOrcusImportXMLParam::CellLinksType::const_iterator it = rParam.maCellLinks.begin(); ScOrcusImportXMLParam::CellLinksType::const_iterator itEnd = rParam.maCellLinks.end(); for (; it != itEnd; ++it) @@ -208,8 +248,8 @@ bool ScOrcusXMLContextImpl::importXML(const ScOrcusImportXMLParam& rParam) } } - // Set range links. { + // Set range links. ScOrcusImportXMLParam::RangeLinksType::const_iterator it = rParam.maRangeLinks.begin(); ScOrcusImportXMLParam::RangeLinksType::const_iterator itEnd = rParam.maRangeLinks.end(); for (; it != itEnd; ++it) diff --git a/sc/source/ui/xmlsource/xmlsourcedlg.cxx b/sc/source/ui/xmlsource/xmlsourcedlg.cxx index 5019306d6e7f..38a1d09954d3 100644 --- a/sc/source/ui/xmlsource/xmlsourcedlg.cxx +++ b/sc/source/ui/xmlsource/xmlsourcedlg.cxx @@ -39,7 +39,8 @@ bool isAttribute(const SvTreeListEntry& rEntry) return pUserData->meType == ScOrcusXMLTreeParam::Attribute; } -OUString getXPath(const SvTreeListBox& rTree, const SvTreeListEntry& rEntry) +OUString getXPath( + const SvTreeListBox& rTree, const SvTreeListEntry& rEntry, std::vector<size_t>& rNamespaces) { OUStringBuffer aBuf; for (const SvTreeListEntry* p = &rEntry; p; p = rTree.GetParent(p)) @@ -48,6 +49,11 @@ OUString getXPath(const SvTreeListBox& rTree, const SvTreeListEntry& rEntry) if (!pItem) continue; + // Collect used namespace. + const ScOrcusXMLTreeParam::EntryData* pData = ScOrcusXMLTreeParam::getUserData(*p); + if (pData) + rNamespaces.push_back(pData->mnNamespaceID); + const SvLBoxString* pStr = static_cast<const SvLBoxString*>(pItem); aBuf.insert(0, pStr->GetText()); aBuf.insert(0, isAttribute(*p) ? '@' : '/'); @@ -428,7 +434,9 @@ namespace { /** * Pick only the leaf elements. */ -void getFieldLinks(ScOrcusImportXMLParam::RangeLink& rRangeLink, const SvTreeListBox& rTree, const SvTreeListEntry& rEntry) +void getFieldLinks( + ScOrcusImportXMLParam::RangeLink& rRangeLink, std::vector<size_t>& rNamespaces, + const SvTreeListBox& rTree, const SvTreeListEntry& rEntry) { const SvTreeListEntries& rChildren = rEntry.GetChildEntries(); if (rChildren.empty()) @@ -439,7 +447,7 @@ void getFieldLinks(ScOrcusImportXMLParam::RangeLink& rRangeLink, const SvTreeLis for (; it != itEnd; ++it) { const SvTreeListEntry& rChild = *it; - OUString aPath = getXPath(rTree, rChild); + OUString aPath = getXPath(rTree, rChild, rNamespaces); const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rChild); if (pUserData && pUserData->mbLeafNode) @@ -450,10 +458,17 @@ void getFieldLinks(ScOrcusImportXMLParam::RangeLink& rRangeLink, const SvTreeLis } // Walk recursively. - getFieldLinks(rRangeLink, rTree, rChild); + getFieldLinks(rRangeLink, rNamespaces, rTree, rChild); } } +void removeDuplicates(std::vector<size_t>& rArray) +{ + std::sort(rArray.begin(), rArray.end()); + std::vector<size_t>::iterator it = std::unique(rArray.begin(), rArray.end()); + rArray.erase(it, rArray.end()); +} + } void ScXMLSourceDlg::OkPressed() @@ -471,7 +486,7 @@ void ScXMLSourceDlg::OkPressed() for (; it != itEnd; ++it) { const SvTreeListEntry& rEntry = **it; - OUString aPath = getXPath(maLbTree, rEntry); + OUString aPath = getXPath(maLbTree, rEntry, aParam.maNamespaces); const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rEntry); aParam.maCellLinks.push_back( @@ -493,14 +508,16 @@ void ScXMLSourceDlg::OkPressed() aRangeLink.maPos = pUserData->maLinkedPos; // Go through all its child elements. - getFieldLinks(aRangeLink, maLbTree, rEntry); + getFieldLinks(aRangeLink, aParam.maNamespaces, maLbTree, rEntry); aParam.maRangeLinks.push_back(aRangeLink); } } - // Now do the import. + // Remove duplicate namespace IDs. + removeDuplicates(aParam.maNamespaces); + // Now do the import. mpXMLContext->importXML(aParam); // Don't forget to broadcast the change. |