Fully support importing of XML with nested repeat elements.

With this change, Calc's XML Source will allow importing XML that
contains nested repeat elements.  It is something the old implementation
did not support.

Change-Id: I73fa1087ccd727390a47007bcfabd411cf007621
Reviewed-on: https://gerrit.libreoffice.org/77941
Tested-by: Jenkins
Reviewed-by: Kohei Yoshida <kohei@libreoffice.org>
This commit is contained in:
Kohei Yoshida
2019-08-22 01:55:00 +02:00
parent 86d55aaad4
commit 52cff86bc7
5 changed files with 72 additions and 31 deletions
+2
View File
@@ -112,6 +112,8 @@ public:
void setTableOpCells(const ScRange& rRange, const ScTabOpParam& rParam);
void fillDownCells(const ScAddress& rPos, SCROW nFillSize);
/**
* Set an array of cell attributes to specified column. This call
* transfers the ownership of the ScAttrEntry array from the caller to the
+35
View File
@@ -537,6 +537,41 @@ void ScDocumentImport::setTableOpCells(const ScRange& rRange, const ScTabOpParam
}
}
void ScDocumentImport::fillDownCells(const ScAddress& rPos, SCROW nFillSize)
{
ScTable* pTab = mpImpl->mrDoc.FetchTable(rPos.Tab());
if (!pTab)
return;
sc::ColumnBlockPosition* pBlockPos = mpImpl->getBlockPosition(rPos.Tab(), rPos.Col());
if (!pBlockPos)
return;
sc::CellStoreType& rCells = pTab->aCol[rPos.Col()].maCells;
ScRefCellValue aRefCell = pTab->aCol[rPos.Col()].GetCellValue(*pBlockPos, rPos.Row());
switch (aRefCell.meType)
{
case CELLTYPE_VALUE:
{
std::vector<double> aCopied(nFillSize, aRefCell.mfValue);
pBlockPos->miCellPos = rCells.set(
pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
break;
}
case CELLTYPE_STRING:
{
std::vector<svl::SharedString> aCopied(nFillSize, *aRefCell.mpString);
pBlockPos->miCellPos = rCells.set(
pBlockPos->miCellPos, rPos.Row()+1, aCopied.begin(), aCopied.end());
break;
}
default:
break;
}
}
void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nCol, Attrs&& rAttrs )
{
ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab);
+3 -1
View File
@@ -587,7 +587,8 @@ class ScOrcusFactory : public orcus::spreadsheet::iface::import_factory
FormulaWithResult,
SharedFormula,
SharedFormulaWithResult,
Matrix
Matrix,
FillDownCells
};
ScAddress const maPos;
@@ -650,6 +651,7 @@ public:
void pushCellStoreToken( const ScAddress& rPos, double fValue );
void pushCellStoreToken(
const ScAddress& rPos, const OUString& rFormula, formula::FormulaGrammar::Grammar eGrammar );
void pushFillDownCellsToken( const ScAddress& rPos, uint32_t nFillSize );
void pushSharedFormulaToken( const ScAddress& rPos, uint32_t nIndex );
void pushMatrixFormulaToken(
+17 -2
View File
@@ -470,6 +470,14 @@ void ScOrcusFactory::finalize()
maDoc.setMatrixCells(aRange, *pArray, rToken.meGrammar);
break;
}
case CellStoreToken::Type::FillDownCells:
{
if (!rToken.mnIndex1)
break;
maDoc.fillDownCells(rToken.maPos, rToken.mnIndex1);
break;
}
default:
;
}
@@ -538,6 +546,12 @@ void ScOrcusFactory::pushCellStoreToken(
maCellStoreTokens.emplace_back(rPos, rFormula, eGrammar);
}
void ScOrcusFactory::pushFillDownCellsToken( const ScAddress& rPos, uint32_t nFillSize )
{
maCellStoreTokens.emplace_back(rPos, CellStoreToken::Type::FillDownCells);
maCellStoreTokens.back().mnIndex1 = nFillSize;
}
void ScOrcusFactory::pushSharedFormulaToken( const ScAddress& rPos, uint32_t nIndex )
{
maCellStoreTokens.emplace_back(rPos, CellStoreToken::Type::SharedFormula);
@@ -1187,9 +1201,10 @@ orcus::spreadsheet::range_size_t ScOrcusSheet::get_sheet_size() const
return ret;
}
void ScOrcusSheet::fill_down_cells(os::row_t /*row*/, os::col_t /*col*/, os::row_t /*range_size*/)
void ScOrcusSheet::fill_down_cells(os::row_t row, os::col_t col, os::row_t range_size)
{
// TODO : implement this.
mrFactory.pushFillDownCellsToken(ScAddress(col, row, mnTab), range_size);
cellInserted();
}
const sc::SharedFormulaGroups& ScOrcusSheet::getSharedFormulaGroups() const
+15 -28
View File
@@ -205,10 +205,10 @@ void ScXMLSourceDlg::LoadSourceFileStructure(const OUString& rPath)
namespace {
/**
* When the current entry is a direct or indirect child of a mappable
* repeat element entry, that entry becomes the reference entry.
* Otherwise the reference entry equals the current entry. A reference
* entry is the entry that stores mapped cell position.
* The current entry is the reference entry for a cell link. For a range
* link, the reference entry is the shallowest repeat element entry up from
* the current entry position. The mapped cell position for a range link is
* stored with the reference entry.
*/
std::unique_ptr<weld::TreeIter> getReferenceEntry(const weld::TreeView& rTree, weld::TreeIter& rCurEntry)
{
@@ -221,14 +221,7 @@ std::unique_ptr<weld::TreeIter> getReferenceEntry(const weld::TreeView& rTree, w
OSL_ASSERT(pUserData);
if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
{
// This is a repeat element.
if (xRefEntry)
{
// Second repeat element encountered. Not good.
std::unique_ptr<weld::TreeIter> xCurEntry(rTree.make_iterator(&rCurEntry));
return xCurEntry;
}
// This is a repeat element - a potential reference entry.
xRefEntry = rTree.make_iterator(xParent.get());
}
bParent = rTree.iter_parent(*xParent);
@@ -332,9 +325,7 @@ void ScXMLSourceDlg::RepeatElementSelected(weld::TreeIter& rEntry)
}
// Check all its child elements / attributes and make sure non of them are
// linked or repeat elements. In the future we will support range linking
// of repeat element who has another repeat elements. But first I need to
// support that scenario in orcus.
// linked.
if (IsChildrenDirty(&rEntry))
{
@@ -420,11 +411,6 @@ bool ScXMLSourceDlg::IsParentDirty(weld::TreeIter* pEntry) const
// This parent is already linked.
return true;
}
if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
{
// This is a repeat element.
return true;
}
}
while (mxLbTree->iter_parent(*xParent));
return false;
@@ -444,10 +430,6 @@ bool ScXMLSourceDlg::IsChildrenDirty(weld::TreeIter* pEntry) const
// Already linked.
return true;
if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
// We don't support linking of nested repeat elements (yet).
return true;
if (pUserData->meType == ScOrcusXMLTreeParam::ElementDefault)
{
// Check recursively.
@@ -478,9 +460,14 @@ void getFieldLinks(
OUString aPath = getXPath(rTree, *xChild, rNamespaces);
const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, *xChild);
if (pUserData && pUserData->mbLeafNode)
if (pUserData)
{
if (!aPath.isEmpty())
if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
// nested repeat element automatically becomes a row-group node.
rRangeLink.maRowGroups.push_back(
OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
if (pUserData->mbLeafNode && !aPath.isEmpty())
// XPath should never be empty anyway, but it won't hurt to check...
rRangeLink.maFieldPaths.push_back(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
}
@@ -533,8 +520,8 @@ void ScXMLSourceDlg::OkPressed()
// Go through all its child elements.
getFieldLinks(aRangeLink, aParam.maNamespaces, *mxLbTree, *rEntry);
// Add the anchor node as a grouping node, which will be used as a
// row position increment point.
// Add the reference entry as a row-group node, which will be used
// as a row position increment point.
OUString aThisEntry = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces);
aRangeLink.maRowGroups.push_back(
OUStringToOString(aThisEntry, RTL_TEXTENCODING_UTF8));