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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user