我在阅读 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();
不返回有关范围的任何信息或有关数据验证的任何信息。有没有人能够掌握源代码并评估公式以获得值(value)?
最佳答案
我能够检索由 2003 年以后的 Excel 工作表的公式定义的数据验证。
我必须解析 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 获取工作表中出现数据验证论坛的 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 必须遍历工作表的 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);
}
}
可能看起来很复杂,但它确实有效。希望对您有所帮助!
关于java - 如何获取引用单元格范围的 Excel 数据验证下拉值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32235774/