Resolves: tdf#88257 handle FILTERXML array/matrix context
... in which subsequent node elements are to be stored in the result
matrix.
Change-Id: Ia980a99a2b9ffba0e651f5d4c2420c8acfb80615
diff --git a/sc/source/core/tool/interpr7.cxx b/sc/source/core/tool/interpr7.cxx
index 7b2624b..2d48c6b 100644
--- a/sc/source/core/tool/interpr7.cxx
+++ b/sc/source/core/tool/interpr7.cxx
@@ -8,6 +8,9 @@
*/
#include "interpre.hxx"
#include "jumpmatrix.hxx"
#include "formulacell.hxx"
#include "scmatrix.hxx"
#include <rtl/strbuf.hxx>
#include <formula/errorcodes.hxx>
#include <svtools/miscopt.hxx>
@@ -33,6 +36,54 @@ void ScInterpreter::ScFilterXML()
sal_uInt8 nParamCount = GetByte();
if (MustHaveParamCount( nParamCount, 2 ) )
{
SCSIZE nMatCols = 1, nMatRows = 1, nNode = 0;
const ScMatrix* pPathMatrix = nullptr;
// In array/matrix context node elements' results are to be
// subsequently stored. Check this before obtaining any argument from
// the stack so the stack type can be used.
if (pJumpMatrix || bMatrixFormula || pCur->IsInForceArray())
{
if (pJumpMatrix)
{
// Single result, GetString() will retrieve the corresponding
// argument and JumpMatrix() will store it at the proper
// position. Note that nMatCols and nMatRows are still 1.
SCSIZE nCurCol = 0, nCurRow = 0;
pJumpMatrix->GetPos( nCurCol, nCurRow);
nNode = nCurRow;
}
else if (bMatrixFormula)
{
// If there is no formula cell then continue with a single
// result.
if (pMyFormulaCell)
{
SCCOL nCols;
SCROW nRows;
pMyFormulaCell->GetMatColsRows( nCols, nRows);
nMatCols = nCols;
nMatRows = nRows;
}
}
else if (GetStackType() == formula::svMatrix)
{
pPathMatrix = pStack[sp-1]->GetMatrix();
if (!pPathMatrix)
{
PushIllegalParameter();
return;
}
pPathMatrix->GetDimensions( nMatCols, nMatRows);
/* TODO: it is unclear what should happen if there are
* different path arguments in matrix elements. We may have to
* evaluate each, and for repeated identical paths use
* subsequent nodes. As is, the path at 0,0 is used as obtained
* by GetString(). */
}
}
OUString aXPathExpression = GetString().getString();
OUString aString = GetString().getString();
if(aString.isEmpty() || aXPathExpression.isEmpty())
@@ -70,8 +121,6 @@ void ScInterpreter::ScFilterXML()
return;
}
rtl::OUString aResult;
switch(pXPathObj->type)
{
case XPATH_UNDEFINED:
@@ -85,30 +134,64 @@ void ScInterpreter::ScFilterXML()
return;
}
size_t nSize = pNodeSet->nodeNr;
if( nSize >= 1 )
const size_t nSize = pNodeSet->nodeNr;
if (nNode >= nSize)
{
if(pNodeSet->nodeTab[0]->type == XML_NAMESPACE_DECL)
// For pJumpMatrix
PushError( formula::NOTAVAILABLE);
return;
}
/* TODO: for nMatCols>1 IF stack type is svMatrix, i.e.
* pPathMatrix!=nullptr, we may want a result matrix with
* nMatCols columns as well, but clarify first how to treat
* differing path elements. */
ScMatrixRef xResMat;
if (nMatRows > 1)
{
xResMat = GetNewMat( 1, nMatRows, true);
if (!xResMat)
{
xmlNsPtr ns = reinterpret_cast<xmlNsPtr>(pNodeSet->nodeTab[0]);
xmlNodePtr cur = reinterpret_cast<xmlNodePtr>(ns->next);
std::shared_ptr<xmlChar> pChar2(xmlNodeGetContent(cur), xmlFree);
aResult = OStringToOUString(OString(reinterpret_cast<char*>(pChar2.get())), RTL_TEXTENCODING_UTF8);
PushError( formula::errCodeOverflow);
return;
}
}
for ( ; nNode < nMatRows; ++nNode)
{
if( nSize > nNode )
{
rtl::OUString aResult;
if(pNodeSet->nodeTab[nNode]->type == XML_NAMESPACE_DECL)
{
xmlNsPtr ns = reinterpret_cast<xmlNsPtr>(pNodeSet->nodeTab[nNode]);
xmlNodePtr cur = reinterpret_cast<xmlNodePtr>(ns->next);
std::shared_ptr<xmlChar> pChar2(xmlNodeGetContent(cur), xmlFree);
aResult = OStringToOUString(OString(reinterpret_cast<char*>(pChar2.get())), RTL_TEXTENCODING_UTF8);
}
else
{
xmlNodePtr cur = pNodeSet->nodeTab[nNode];
std::shared_ptr<xmlChar> pChar2(xmlNodeGetContent(cur), xmlFree);
aResult = OStringToOUString(OString(reinterpret_cast<char*>(pChar2.get())), RTL_TEXTENCODING_UTF8);
}
if (xResMat)
xResMat->PutString( mrStrPool.intern( aResult), 0, nNode);
else
PushString(aResult);
}
else
{
xmlNodePtr cur = pNodeSet->nodeTab[0];
std::shared_ptr<xmlChar> pChar2(xmlNodeGetContent(cur), xmlFree);
aResult = OStringToOUString(OString(reinterpret_cast<char*>(pChar2.get())), RTL_TEXTENCODING_UTF8);
if (xResMat)
xResMat->PutError( formula::NOTAVAILABLE, 0, nNode);
else
PushError( formula::NOTAVAILABLE );
}
}
else
{
PushError( formula::errNoValue );
return;
}
if (xResMat)
PushMatrix( xResMat);
}
PushString(aResult);
break;
case XPATH_BOOLEAN:
{