Ed *_*and 2 comments apache-poi
我使用该cloneSheet方法在同一工作簿中复制已包含注释的工作表。然后,新注释被添加到这个新工作表中并保存 Excel。
当使用 Excel 365 打开文件时,它抱怨/xl/comments1.xml并恢复了该文件。新创建的评论可用。克隆中的注释在恢复期间将被删除。
打开 zip 文件并查看/xl/comments1.xml,它显示出差异。
这是方法的问题cloneSheet还是微软正在使用新的方法?
尽管该apache poi项目已经成熟,但它还远未完成。因此,需要使用它的人必须了解所使用的文件系统的内部结构。
那么注释是如何存储在 Excel 的 Office Open XML ( *.xlsx) 文件系统中的呢?
整个文件系统是一个 ZIP 存档。第一张纸的图纸数据位于/xl/worksheets/sheet1.xml该 ZIP 内。那里的XML有
...
<legacyDrawing r:id="rId2"/>
...
Run Code Online (Sandbox Code Playgroud)
它指向在第一张表的关系部分 XML 中VMLDrawing具有的遗留。rId2
第一张表的关系部分 XML/xl/worksheets/_rels/sheet1.xml.rels如下所示
<Relationships>
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" Target="../comments1.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" Target="../drawings/vmlDrawing1.vml"/>
...
</Relationships>
Run Code Online (Sandbox Code Playgroud)
所以rId2指向/xl/drawings/vmlDrawing1.vml并rId3指向/xl/comments1.xml。
因此,vmlDrawing1.vml包含工作表上评论形状的锚点,而“comments1.xml”包含评论内容。
现在public XSSFSheet cloneSheet(intsheetNum, String newName)的方法在做什么XSSFWorkbook?
首先,它复制所有工作表的关系。VMLDrawing因此,与和各部分的关系也Comments被复制。因此,如果我们克隆第一张纸,那么克隆后将/xl/worksheets/_rels/sheet2.xml.rels具有与之前相同的内容/xl/worksheets/_rels/sheet1.xml.rels。
但随后它指出:“尚不支持带有注释的克隆表。” <legacyDrawing r:id="rId2"/>并从工作表的 XML 中删除。但之前复制的关系并没有被删除。
因此,我们得到了一个克隆工作表,工作表中没有链接注释,但与注释及其形状集有关系。
如果我们现在在该克隆表中创建新注释,那么/xl/drawings/vmlDrawing2.vml也会创建新注释,包含其在 中的关系/xl/worksheets/_rels/sheet2.xml.rels。之后我们还有一个/xl/worksheets/_rels/sheet2.xml.relswhich 指向/xl/drawings/vmlDrawing1.vml和to /xl/drawings/vmlDrawing2.vml。但这是不允许的,因此 Excel 在打开时会抛出错误并建议修复。
此外,新创建的注释存储在/xl/comments1.xml其中也是错误的,因为每个工作表都需要自己的注释部分。发生这种情况是因为在克隆字段时,该XSSFSheet字段private CommentsTable sheetComments也被克隆并包含源表的旧注释表。
因此,为了能够在克隆工作表中创建注释,我们需要消除错误的关系,并CommentsTable消除sheetComments.XSSFSheet
例子:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLDocumentPart.RelationPart;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
class ExcelCloneSheetHavingComments {
public static void main(String[] args) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("ExcelHavingComments.xlsx"));
Sheet sheetClone = workbook.cloneSheet(0);
workbook.setSheetName(workbook.getSheetIndex(sheetClone), "Cloned first Sheet");
if (sheetClone instanceof XSSFSheet) {
XSSFSheet xssfSheet = (XSSFSheet)sheetClone;
// get rid of the wrong relations
for (POIXMLDocumentPart.RelationPart relationPart : xssfSheet.getRelationParts()) {
if (relationPart.getDocumentPart() instanceof org.apache.poi.xssf.usermodel.XSSFVMLDrawing
|| relationPart.getDocumentPart() instanceof org.apache.poi.xssf.model.CommentsTable) {
relationPart.getRelationship().getSource().removeRelationship(relationPart.getRelationship().getId());
}
}
// get rid of the wrong org.apache.poi.xssf.model.CommentsTable
Field sheetComments = XSSFSheet.class.getDeclaredField("sheetComments");
sheetComments.setAccessible(true);
sheetComments.set(xssfSheet, null);
}
Drawing drawing = sheetClone.createDrawingPatriarch();
Comment comment = drawing.createCellComment(drawing.createAnchor(0, 0, 0, 0, 2, 1, 4, 4));
comment.setString(new XSSFRichTextString("Comment in Cell C2 in cloned sheet"));
workbook.write(new FileOutputStream("CopyOfExcelHavingComments.xlsx"));
workbook.close();
}
}
Run Code Online (Sandbox Code Playgroud)
这不会复制源表中的注释。当然,现在也可以在源工作表中使用Sheet.getCellComments,然后Drawing.createCellComment在克隆工作表中使用。
| 归档时间: |
|
| 查看次数: |
1087 次 |
| 最近记录: |