如何获取 Excel 引用单元格范围的数据验证下拉值

How to Get Excel Data Validations Drop Down values for Referenced Cell Ranges

我在阅读 Excel 文档时偶然发现了一个问题,特别是从单元格中获取下拉值(数据验证)。我能够获得明确定义的值。

我可以通过查看单元格是否在 CellRangeAddress 中来获取值(720x486 等)。:

    Map<CellRangeAddress, String[]> dropDownValues = new HashMap<>();
    List<? extends DataValidation> dataValidations = sheet.getDataValidations();

    for(DataValidation dataValidation : dataValidations)
    {
        for(CellRangeAddress cellRangeAddress : dataValidation.getRegions().getCellRangeAddresses())
        {
            String[] explicitListValues = dataValidation.getValidationConstraint().getExplicitListValues();
            if(explicitListValues == null)
            {
                continue;
            }
            dropDownValues.put(cellRangeAddress, explicitListValues);
        }
    }

以上代码仅适用于显式值。我看到的问题是在单元格的数据验证源中定义范围时:

sheet.getDataValidations();

不return任何关于数据验证范围或任何信息的内容。有没有人能够掌握源代码并评估公式以获得价值?

我能够检索由 Excel 比 2003 年更新的工作表的公式定义的数据验证。

我必须解析 XSSFSheet 以获取特定信息,然后重建和评估公式。

这是我为获得所有 DataValidation 值所做的工作:

Map<CellRangeAddress, String[]> dropDownValues = new HashMap<>();

List<ExtendedDataValidations> extendedDataValidationsList = getExtendedDataValidations(sheet);
for (ExtendedDataValidations extendedDataValidations : extendedDataValidationsList)
{
    AreaReference formulaReference = new AreaReference(extendedDataValidations.formula);
    CellReference[] allReferencedCells = formulaReference.getAllReferencedCells();
    FormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator();
    String[] values = new String[allReferencedCells.length];
    for (int j = 0; j < allReferencedCells.length; j++)
    {
        CellReference cellReference = allReferencedCells[j];
        Sheet valueSheet = wb.getSheet(cellReference.getSheetName());
        Cell cell = valueSheet.getRow(cellReference.getRow()).getCell(cellReference.getCol());
        CellValue evaluate = formulaEvaluator.evaluate(cell);
        values[j] = StringUtils.trimToEmpty(StringUtils.removeStart(StringUtils.removeEnd(evaluate.formatAsString(), "\""), "\""));
    }

    String stRef = extendedDataValidations.sqref;
    String[] regions = stRef.split(" ");
    for (String region : regions)
    {
        String[] parts = region.split(":");
        CellReference begin = new CellReference(parts[0]);
        CellReference end = parts.length > 1 ? new CellReference(parts[1]) : begin;
        CellRangeAddress cellRangeAddress = new CellRangeAddress(begin.getRow(), end.getRow(), begin.getCol(), end.getCol());
        dropDownValues.put(cellRangeAddress, values);
    }
}

此外,我为公式和单元格引用定义了一个 Struc。

private static class ExtendedDataValidations
{
    public String formula;
    public String sqref;
}

getExtendedDataValidations 获取了 sheet:

中出现数据验证论坛的 CTExtensionList
public static List<ExtendedDataValidations> getExtendedDataValidations(Sheet sheet)
{
    List<ExtendedDataValidations> extendedDataValidationsList = new ArrayList<>();

    if (sheet instanceof XSSFSheet)
    {
        CTExtensionList extLst = ((XSSFSheet) sheet).getCTWorksheet().getExtLst();
        if (extLst == null)
        {
            return extendedDataValidationsList;
        }

        CTExtension[] extArray = extLst.getExtArray();
        List<Node> dataValidationNodes = new ArrayList<>();
        for (CTExtension anExtArray : extArray)
        {
            searchForDataValidation(anExtArray.getDomNode(), dataValidationNodes);
        }

        for (Node dataValidationNode : dataValidationNodes)
        {
            ExtendedDataValidations dataValidations = new ExtendedDataValidations();
            getDataValidationInfo(dataValidationNode, dataValidations);
            extendedDataValidationsList.add(dataValidations);
        }

    }

    return extendedDataValidationsList;
}

searchForDataValidation 必须遍历 sheet 的 DOM 节点以查找有关 DataValidation 的特定信息。如果找到将其保存在列表中:

private static void searchForDataValidation(Node node, List<Node> nodesInQuestion)
{
    if (StringUtils.equalsIgnoreCase("x14:dataValidation", node.getNodeName()))
    {
        nodesInQuestion.add(node);
        return;
    }

    for (int i = 0; i < node.getChildNodes().getLength(); i++)
    {
        searchForDataValidation(node.getChildNodes().item(i), nodesInQuestion);
    }
}

getDataValidationInfo 负责获取公式和单元格引用。

private static void getDataValidationInfo(Node node, ExtendedDataValidations dataValidations)
{
    if (StringUtils.equalsIgnoreCase("#text", node.getNodeName()))
    {
        if (StringUtils.equalsIgnoreCase("xm:sqref", node.getParentNode().getNodeName()))
        {
            dataValidations.sqref = node.getNodeValue();
        }
        else if (StringUtils.equalsIgnoreCase("xm:f", node.getParentNode().getNodeName()))
        {
            dataValidations.formula = node.getNodeValue();
        }
        return;
    }

    for (int i = 0; i < node.getChildNodes().getLength(); i++)
    {
        getDataValidationInfo(node.getChildNodes().item(i), dataValidations);
    }
}

可能看起来很复杂,但它确实有效。希望对您有所帮助!