You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从剪贴板XML字符串实例化XSSFWorkbook以处理Excel数据?

问题

我正尝试实现一个可将Excel行粘贴到SpreadsheetView控件(ControlsFX)中的功能。目前已成功获取剪贴板对应的XML字符串,内容如下:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
 <Styles>
  <Style ss:ID="Default" ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID="s113">
   <Alignment ss:Horizontal="Center" ss:Vertical="Top"/>
   <Borders>
    <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/>
    <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/>
    <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/>
    <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/>
   </Borders>
  </Style>
 </Styles>
 <Worksheet ss:Name="Nouvelle feuille">
  <Table ss:ExpandedColumnCount="16384" ss:ExpandedRowCount="1" x:FullRows="1"
   ss:DefaultRowHeight="15">
   <Column ss:Width="86.25"/>
   <Column ss:Width="96"/>
   <Column ss:Width="54.75"/>
   <Column ss:Width="51.75"/>
   <Column ss:Width="53.25"/>
   <Column ss:Width="69.75"/>
   <Column ss:Width="27.75"/>
   <Column ss:Width="56.25"/>
   <Column ss:Width="58.5"/>
   <Column ss:Width="23.25"/>
   <Column ss:Width="163.5"/>
   <Column ss:Index="13" ss:Width="77.25"/>
   <Row>
    <Cell ss:StyleID="s113"><Data ss:Type="Number">1</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">10</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">101</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">1</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">010</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">10</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">B</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="Number">1</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="Number">101</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="Number">103</Data></Cell>
    <Cell ss:StyleID="s113"><Data ss:Type="String">test</Data></Cell>
    <Cell ss:Index="13" ss:StyleID="s113"><Data ss:Type="String">13</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>

我希望通过该XML字符串创建XSSFWorkbook实例,以便轻松处理其中的数据,请问这是否可行?

回答

直接用这个XML创建XSSFWorkbook不可行。原因是你拿到的XML属于Excel的SpreadsheetML格式(旧版Office XML规范,对应Excel 2003及更早版本),而XSSFWorkbook是Apache POI专门用来处理OOXML格式(即.xlsx,Excel 2007+的开放XML格式)的类,两者的文件结构完全不兼容。

不过有两种可行的处理方案:

方案1:直接解析SpreadsheetML XML(推荐)

既然已经拿到了XML字符串,直接用Java的XML解析工具提取数据更高效,不需要额外格式转换。可以定位到XML中的<Row>和<Cell>节点,提取数据后直接转换成SpreadsheetView需要的格式:

// 假设xmlStr是剪贴板获取到的XML字符串
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlStr)));

// 处理命名空间,避免找不到节点
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
    @Override
    public String getNamespaceURI(String prefix) {
        if ("ss".equals(prefix)) {
            return "urn:schemas-microsoft-com:office:spreadsheet";
        }
        return NamespaceContext.DEFAULT_NS_PREFIX;
    }

    @Override
    public String getPrefix(String namespaceURI) { return null; }
    @Override
    public Iterator<?> getPrefixes(String namespaceURI) { return null; }
});

// 提取所有行数据
NodeList rowNodes = (NodeList) xpath.evaluate("//ss:Row", doc, XPathConstants.NODESET);
ObservableList<ObservableList<Object>> data = FXCollections.observableArrayList();

for (int i = 0; i < rowNodes.getLength(); i++) {
    Node rowNode = rowNodes.item(i);
    NodeList cellNodes = (NodeList) xpath.evaluate("./ss:Cell", rowNode, XPathConstants.NODESET);
    ObservableList<Object> rowData = FXCollections.observableArrayList();

    for (int j = 0; j < cellNodes.getLength(); j++) {
        Node cellNode = cellNodes.item(j);
        String dataType = xpath.evaluate("./ss:Data/@ss:Type", cellNode);
        String value = xpath.evaluate("./ss:Data/text()", cellNode);

        // 根据数据类型转换值
        if ("Number".equals(dataType)) {
            rowData.add(Double.parseDouble(value));
        } else {
            rowData.add(value);
        }
    }
    data.add(rowData);
}

// 将数据设置到SpreadsheetView
spreadsheetView.setItems(data);

方案2:转换为XSSFWorkbook支持的格式

如果一定要用XSSFWorkbook处理,可以先把SpreadsheetML转换成.xlsx格式:

  1. 将XML字符串写入临时文件(后缀设为.xml)
  2. 用Apache POI的WorkbookFactory读取该文件,会自动返回对应旧版格式的HSSFWorkbook
  3. 把HSSFWorkbook的数据复制到新创建的XSSFWorkbook中

示例代码:

// 写入临时XML文件
File tempXml = File.createTempFile("excel_clipboard", ".xml");
try (FileWriter writer = new FileWriter(tempXml)) {
    writer.write(xmlStr);
}

// 读取旧版Excel格式文件
Workbook hssfWorkbook = WorkbookFactory.create(tempXml);

// 转换为XSSFWorkbook
XSSFWorkbook xssfWorkbook = new XSSFWorkbook();
Sheet srcSheet = hssfWorkbook.getSheetAt(0);
Sheet destSheet = xssfWorkbook.createSheet();

// 复制行数据
for (int rowNum = 0; rowNum <= srcSheet.getLastRowNum(); rowNum++) {
    Row srcRow = srcSheet.getRow(rowNum);
    Row destRow = destSheet.createRow(rowNum);
    if (srcRow != null) {
        for (int cellNum = 0; cellNum < srcRow.getLastCellNum(); cellNum++) {
            Cell srcCell = srcRow.getCell(cellNum);
            if (srcCell != null) {
                Cell destCell = destRow.createCell(cellNum);
                // 根据单元格类型处理值转换
                switch (srcCell.getCellType()) {
                    case NUMERIC:
                        destCell.setCellValue(srcCell.getNumericCellValue());
                        break;
                    case STRING:
                        destCell.setCellValue(srcCell.getStringCellValue());
                        break;
                    default:
                        destCell.setCellValue(srcCell.toString());
                }
            }
        }
    }
}

// 后续可使用XSSFWorkbook处理数据
// ...

// 清理临时文件
tempXml.deleteOnExit();

注意:方案2需要额外的格式转换步骤,性能不如方案1。如果只是为了给SpreadsheetView填充数据,优先选方案1。


内容的提问来源于stack exchange,提问作者Luca170598

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:11:17