Search in sources :

Example 1 with StringPtg

use of org.apache.poi.ss.formula.ptg.StringPtg in project poi by apache.

the class TestFormulaParser method testMacroFunction.

// copied from org.apache.poi.hssf.model.TestFormulaParser
@Test
public void testMacroFunction() throws Exception {
    // testNames.xlsm contains a VB function called 'myFunc'
    final String testFile = "testNames.xlsm";
    XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook(testFile);
    try {
        XSSFEvaluationWorkbook workbook = XSSFEvaluationWorkbook.create(wb);
        //Expected ptg stack: [NamePtg(myFunc), StringPtg(arg), (additional operands would go here...), FunctionPtg(myFunc)]
        Ptg[] ptg = FormulaParser.parse("myFunc(\"arg\")", workbook, FormulaType.CELL, -1);
        assertEquals(3, ptg.length);
        // the name gets encoded as the first operand on the stack
        NameXPxg tname = (NameXPxg) ptg[0];
        assertEquals("myFunc", tname.toFormulaString());
        // the function's arguments are pushed onto the stack from left-to-right as OperandPtgs
        StringPtg arg = (StringPtg) ptg[1];
        assertEquals("arg", arg.getValue());
        // The external FunctionPtg is the last Ptg added to the stack
        // During formula evaluation, this Ptg pops off the the appropriate number of
        // arguments (getNumberOfOperands()) and pushes the result on the stack 
        AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[2];
        assertTrue(tfunc.isExternalFunction());
        // confirm formula parsing is case-insensitive
        FormulaParser.parse("mYfUnC(\"arg\")", workbook, FormulaType.CELL, -1);
        // confirm formula parsing doesn't care about argument count or type
        // this should only throw an error when evaluating the formula.
        FormulaParser.parse("myFunc()", workbook, FormulaType.CELL, -1);
        FormulaParser.parse("myFunc(\"arg\", 0, TRUE)", workbook, FormulaType.CELL, -1);
        // A completely unknown formula name (not saved in workbook) should still be parseable and renderable
        // but will throw an NotImplementedFunctionException or return a #NAME? error value if evaluated.
        FormulaParser.parse("yourFunc(\"arg\")", workbook, FormulaType.CELL, -1);
        // Make sure workbook can be written and read
        XSSFTestDataSamples.writeOutAndReadBack(wb).close();
    // Manually check to make sure file isn't corrupted
    // TODO: develop a process for occasionally manually reviewing workbooks
    // to verify workbooks are not corrupted
    /*
            final File fileIn = XSSFTestDataSamples.getSampleFile(testFile);
            final File reSavedFile = new File(fileIn.getParentFile(), fileIn.getName().replace(".xlsm", "-saved.xlsm"));
            final FileOutputStream fos = new FileOutputStream(reSavedFile);
            wb.write(fos);
            fos.close();
            */
    } finally {
        wb.close();
    }
}
Also used : XSSFEvaluationWorkbook(org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook) Ptg(org.apache.poi.ss.formula.ptg.Ptg) StringPtg(org.apache.poi.ss.formula.ptg.StringPtg) AbstractFunctionPtg(org.apache.poi.ss.formula.ptg.AbstractFunctionPtg) NameXPxg(org.apache.poi.ss.formula.ptg.NameXPxg) XSSFWorkbook(org.apache.poi.xssf.usermodel.XSSFWorkbook) AbstractFunctionPtg(org.apache.poi.ss.formula.ptg.AbstractFunctionPtg) StringPtg(org.apache.poi.ss.formula.ptg.StringPtg) Test(org.junit.Test)

Example 2 with StringPtg

use of org.apache.poi.ss.formula.ptg.StringPtg in project poi by apache.

the class TestFormulaParser method testMacroFunction.

@Test
public void testMacroFunction() throws IOException {
    // testNames.xls contains a VB function called 'myFunc'
    final String testFile = "testNames.xls";
    HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(testFile);
    try {
        HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(wb);
        //Expected ptg stack: [NamePtg(myFunc), StringPtg(arg), (additional operands go here...), FunctionPtg(myFunc)]
        Ptg[] ptg = FormulaParser.parse("myFunc(\"arg\")", book, FormulaType.CELL, -1);
        assertEquals(3, ptg.length);
        // the name gets encoded as the first operand on the stack
        NamePtg tname = (NamePtg) ptg[0];
        assertEquals("myFunc", tname.toFormulaString(book));
        // the function's arguments are pushed onto the stack from left-to-right as OperandPtgs
        StringPtg arg = (StringPtg) ptg[1];
        assertEquals("arg", arg.getValue());
        // The external FunctionPtg is the last Ptg added to the stack
        // During formula evaluation, this Ptg pops off the the appropriate number of
        // arguments (getNumberOfOperands()) and pushes the result on the stack
        //FuncVarPtg
        AbstractFunctionPtg tfunc = (AbstractFunctionPtg) ptg[2];
        assertTrue(tfunc.isExternalFunction());
        // confirm formula parsing is case-insensitive
        FormulaParser.parse("mYfUnC(\"arg\")", book, FormulaType.CELL, -1);
        // confirm formula parsing doesn't care about argument count or type
        // this should only throw an error when evaluating the formula.
        FormulaParser.parse("myFunc()", book, FormulaType.CELL, -1);
        FormulaParser.parse("myFunc(\"arg\", 0, TRUE)", book, FormulaType.CELL, -1);
        // A completely unknown formula name (not saved in workbook) should still be parseable and renderable
        // but will throw an NotImplementedFunctionException or return a #NAME? error value if evaluated.
        FormulaParser.parse("yourFunc(\"arg\")", book, FormulaType.CELL, -1);
        // Verify that myFunc and yourFunc were successfully added to Workbook names
        HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
        try {
            // HSSFWorkbook/EXCEL97-specific side-effects user-defined function names must be added to Workbook's defined names in order to be saved.
            assertNotNull(wb2.getName("myFunc"));
            assertEqualsIgnoreCase("myFunc", wb2.getName("myFunc").getNameName());
            assertNotNull(wb2.getName("yourFunc"));
            assertEqualsIgnoreCase("yourFunc", wb2.getName("yourFunc").getNameName());
        // Manually check to make sure file isn't corrupted
        // TODO: develop a process for occasionally manually reviewing workbooks
        // to verify workbooks are not corrupted
        /*
                final File fileIn = HSSFTestDataSamples.getSampleFile(testFile);
                final File reSavedFile = new File(fileIn.getParentFile(), fileIn.getName().replace(".xls", "-saved.xls"));
                FileOutputStream fos = new FileOutputStream(reSavedFile);
                wb2.write(fos);
                fos.close();
                */
        } finally {
            wb2.close();
        }
    } finally {
        wb.close();
    }
}
Also used : NumberPtg(org.apache.poi.ss.formula.ptg.NumberPtg) ArrayPtg(org.apache.poi.ss.formula.ptg.ArrayPtg) AttrPtg(org.apache.poi.ss.formula.ptg.AttrPtg) PercentPtg(org.apache.poi.ss.formula.ptg.PercentPtg) RangePtg(org.apache.poi.ss.formula.ptg.RangePtg) AddPtg(org.apache.poi.ss.formula.ptg.AddPtg) EqualPtg(org.apache.poi.ss.formula.ptg.EqualPtg) UnaryMinusPtg(org.apache.poi.ss.formula.ptg.UnaryMinusPtg) NameXPtg(org.apache.poi.ss.formula.ptg.NameXPtg) RefPtg(org.apache.poi.ss.formula.ptg.RefPtg) DividePtg(org.apache.poi.ss.formula.ptg.DividePtg) GreaterThanPtg(org.apache.poi.ss.formula.ptg.GreaterThanPtg) MultiplyPtg(org.apache.poi.ss.formula.ptg.MultiplyPtg) Ref3DPtg(org.apache.poi.ss.formula.ptg.Ref3DPtg) StringPtg(org.apache.poi.ss.formula.ptg.StringPtg) ErrPtg(org.apache.poi.ss.formula.ptg.ErrPtg) Ptg(org.apache.poi.ss.formula.ptg.Ptg) Area3DPtg(org.apache.poi.ss.formula.ptg.Area3DPtg) NamePtg(org.apache.poi.ss.formula.ptg.NamePtg) MemAreaPtg(org.apache.poi.ss.formula.ptg.MemAreaPtg) ConcatPtg(org.apache.poi.ss.formula.ptg.ConcatPtg) UnaryPlusPtg(org.apache.poi.ss.formula.ptg.UnaryPlusPtg) BoolPtg(org.apache.poi.ss.formula.ptg.BoolPtg) IntersectionPtg(org.apache.poi.ss.formula.ptg.IntersectionPtg) AbstractFunctionPtg(org.apache.poi.ss.formula.ptg.AbstractFunctionPtg) IntPtg(org.apache.poi.ss.formula.ptg.IntPtg) UnionPtg(org.apache.poi.ss.formula.ptg.UnionPtg) FuncVarPtg(org.apache.poi.ss.formula.ptg.FuncVarPtg) SubtractPtg(org.apache.poi.ss.formula.ptg.SubtractPtg) FuncPtg(org.apache.poi.ss.formula.ptg.FuncPtg) MissingArgPtg(org.apache.poi.ss.formula.ptg.MissingArgPtg) MemFuncPtg(org.apache.poi.ss.formula.ptg.MemFuncPtg) PowerPtg(org.apache.poi.ss.formula.ptg.PowerPtg) AreaPtg(org.apache.poi.ss.formula.ptg.AreaPtg) ParenthesisPtg(org.apache.poi.ss.formula.ptg.ParenthesisPtg) NamePtg(org.apache.poi.ss.formula.ptg.NamePtg) AbstractFunctionPtg(org.apache.poi.ss.formula.ptg.AbstractFunctionPtg) UnicodeString(org.apache.poi.hssf.record.common.UnicodeString) StringPtg(org.apache.poi.ss.formula.ptg.StringPtg) HSSFWorkbook(org.apache.poi.hssf.usermodel.HSSFWorkbook) HSSFEvaluationWorkbook(org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook) Test(org.junit.Test)

Example 3 with StringPtg

use of org.apache.poi.ss.formula.ptg.StringPtg in project poi by apache.

the class TestFormulaParser method confirmStringParse.

/**
     * To aid readability the parameters have been encoded with single quotes instead of double
     * quotes.  This method converts single quotes to double quotes before performing the parse
     * and result check.
     */
private static void confirmStringParse(String singleQuotedValue) {
    // formula: internal quotes become double double, surround with double quotes
    String formula = '"' + singleQuotedValue.replaceAll("'", "\"\"") + '"';
    String expectedValue = singleQuotedValue.replace('\'', '"');
    StringPtg sp = (StringPtg) parseSingleToken(formula, StringPtg.class);
    assertEquals(expectedValue, sp.getValue());
}
Also used : UnicodeString(org.apache.poi.hssf.record.common.UnicodeString) StringPtg(org.apache.poi.ss.formula.ptg.StringPtg)

Example 4 with StringPtg

use of org.apache.poi.ss.formula.ptg.StringPtg in project poi by apache.

the class FormulaParser method parseNonRange.

/**
     * Parses simple factors that are not primitive ranges or range components
     * i.e. '!', ':'(and equiv '...') do not appear
     * Examples
     * <pre>
     *   my.named...range.
     *   foo.bar(123.456, "abc")
     *   123.456
     *   "abc"
     *   true
     * </pre>
     */
private ParseNode parseNonRange(int savePointer) {
    resetPointer(savePointer);
    if (Character.isDigit(look)) {
        return new ParseNode(parseNumber());
    }
    if (look == '"') {
        return new ParseNode(new StringPtg(parseStringLiteral()));
    }
    // from now on we can only be dealing with non-quoted identifiers
    // which will either be named ranges or functions
    String name = parseAsName();
    if (look == '(') {
        return function(name);
    }
    if (look == '[') {
        return parseStructuredReference(name);
    }
    if (name.equalsIgnoreCase("TRUE") || name.equalsIgnoreCase("FALSE")) {
        return new ParseNode(BoolPtg.valueOf(name.equalsIgnoreCase("TRUE")));
    }
    if (_book == null) {
        // Only test cases omit the book (expecting it not to be needed)
        throw new IllegalStateException("Need book to evaluate name '" + name + "'");
    }
    EvaluationName evalName = _book.getName(name, _sheetIndex);
    if (evalName == null) {
        throw new FormulaParseException("Specified named range '" + name + "' does not exist in the current workbook.");
    }
    if (evalName.isRange()) {
        return new ParseNode(evalName.createPtg());
    }
    // TODO - what about NameX ?
    throw new FormulaParseException("Specified name '" + name + "' is not a range as expected.");
}
Also used : StringPtg(org.apache.poi.ss.formula.ptg.StringPtg)

Example 5 with StringPtg

use of org.apache.poi.ss.formula.ptg.StringPtg in project poi by apache.

the class FormulaParser method parseSimpleFactor.

/**
     * factors (without ^ or % )
     */
private ParseNode parseSimpleFactor() {
    SkipWhite();
    switch(look) {
        case '#':
            return new ParseNode(ErrPtg.valueOf(parseErrorLiteral()));
        case '-':
            Match('-');
            return parseUnary(false);
        case '+':
            Match('+');
            return parseUnary(true);
        case '(':
            Match('(');
            ParseNode inside = unionExpression();
            Match(')');
            return new ParseNode(ParenthesisPtg.instance, inside);
        case '"':
            return new ParseNode(new StringPtg(parseStringLiteral()));
        case '{':
            Match('{');
            ParseNode arrayNode = parseArray();
            Match('}');
            return arrayNode;
    }
    // see https://support.office.com/en-us/article/Define-and-use-names-in-formulas-4d0f13ac-53b7-422e-afd2-abd7ff379c64?ui=en-US&rs=en-US&ad=US#bmsyntax_rules_for_names
    if (IsAlpha(look) || Character.isDigit(look) || look == '\'' || look == '[' || look == '_' || look == '\\') {
        return parseRangeExpression();
    }
    if (look == '.') {
        return new ParseNode(parseNumber());
    }
    throw expected("cell ref or constant literal");
}
Also used : StringPtg(org.apache.poi.ss.formula.ptg.StringPtg)

Aggregations

StringPtg (org.apache.poi.ss.formula.ptg.StringPtg)8 UnicodeString (org.apache.poi.hssf.record.common.UnicodeString)4 Ptg (org.apache.poi.ss.formula.ptg.Ptg)4 Test (org.junit.Test)4 AbstractFunctionPtg (org.apache.poi.ss.formula.ptg.AbstractFunctionPtg)3 AddPtg (org.apache.poi.ss.formula.ptg.AddPtg)3 AttrPtg (org.apache.poi.ss.formula.ptg.AttrPtg)3 BoolPtg (org.apache.poi.ss.formula.ptg.BoolPtg)3 FuncPtg (org.apache.poi.ss.formula.ptg.FuncPtg)3 FuncVarPtg (org.apache.poi.ss.formula.ptg.FuncVarPtg)3 IntPtg (org.apache.poi.ss.formula.ptg.IntPtg)3 MultiplyPtg (org.apache.poi.ss.formula.ptg.MultiplyPtg)3 RefPtg (org.apache.poi.ss.formula.ptg.RefPtg)3 HSSFWorkbook (org.apache.poi.hssf.usermodel.HSSFWorkbook)2 Area3DPtg (org.apache.poi.ss.formula.ptg.Area3DPtg)2 AreaPtg (org.apache.poi.ss.formula.ptg.AreaPtg)2 ArrayPtg (org.apache.poi.ss.formula.ptg.ArrayPtg)2 ConcatPtg (org.apache.poi.ss.formula.ptg.ConcatPtg)2 DividePtg (org.apache.poi.ss.formula.ptg.DividePtg)2 EqualPtg (org.apache.poi.ss.formula.ptg.EqualPtg)2