将所有types的RELATIONS从一个工作簿复制到新的工作簿Apache POI XSSFWorkbook

我一直在试图从一个工作簿中把关系复制到另一个新创build的工作簿上。 到目前为止,我已经试过这个:

XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook POIXMLDocument upcastOldwb = oldWB; //Upcasting POIXMLDocument upcastNewwb = newWB; //Upcasting for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) { upcastNewwb.getPackagePart().getRelatedPart(pr).addRelationship(pr.getTargetURI(),pr.getTargetMode(), pr.getRelationshipType()); } 

在这一点上,我得到这个错误:

 Exception in thread "main" java.lang.IllegalArgumentException: Relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage@5ffdc730 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet - source=/xl/workbook.xml - target=/xl/worksheets/sheet1.xml,targetMode=INTERNAL doesn't start with this part /xl/workbook.xml 

首先,我承认我不知道我采取的做法是否正确。 我只是试图将关系从一个工作簿复制到另一个工作簿。 任何帮助将不胜感激。

谢谢

编辑2

当你说这个部分必须先存在时,这就是你所说的吗?

 XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook POIXMLDocument upcastOldwb = oldWB; //Upcasting POIXMLDocument upcastNewwb = newWB; //Upcasting //Different code from above (the actual question). Is this what you thought I missed? for (PackageRelationship pr : upcastOldwb.getPackagePart().getRelationships()) { URI target = pr.getTargetURI(); if(target.getFragment() != null) { String t = target.toString(); try { target = new URI( t.substring(0, t.indexOf('#')) ); } catch(URISyntaxException e) { throw new InvalidFormatException("Invalid target URI: " + target); } } PackagePartName relName = PackagingURIHelper.createPartName(target); upcastNewwb.getPackagePart().getPackage().createPart(relName, upcastOldwb.getPackagePart().getContentType()); } 

编辑1:

我的最终目标是将工作表从一个工作簿复制到另一个工作簿。 还有其他build议/解决scheme。 我甚至自己实现了一个,没有看其他解决scheme。

我实施了Gagravarr给出的build议。 事实certificate,我的实现与在SO和coderanch上find的其他解决scheme的99%相同。 但是这个解决scheme存在问题。 如果工作表包含表格,图片,graphics等,那么这些解决scheme就不能正常工作。

然后我想到了一个聪明的方法来将图纸复制到新的工作簿: 通过消除的过程! 这个解决scheme是最好的。 它保持一切完好,没有图表,图表,图片会打破。 但是,正如你所看到的那样,这是一种拙劣的方式。 不是很酷的方式。 所以我想要实施一些合适的方法。 或者是专业的开发者

为此,我研究了XSSFWorkbook.cloneSheet(...)方法,以及Apache的开发人员如何实现它。 我正试图复制它。 到目前为止,我的企图都是按照计划进行的,只有一个小问题。 这个问题是上面的原始问题。 让我先告诉你我的代码:

 public static void main(String[] args) throws Exception { XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\faraz\\Documents\\pivottablesurvey.xlsx")); XSSFWorkbook newWB = new XSSFWorkbook(); for (int i = 0; i < oldWB.getNumberOfSheets(); i++) { XSSFSheet sheetFromOldWB = (XSSFSheet) oldWB.getSheetAt(i); XSSFSheet sheetForNewWB = (XSSFSheet) newWB.createSheet(sheetFromOldWB.getSheetName()); /* * Behold! Below this point, I am trying to mimic XSSFWorkbook.cloneSheet(...) method */ List<RelationPart> rels = sheetFromOldWB.getRelationParts(); XSSFDrawing dg = null; for(RelationPart rp : rels) { POIXMLDocumentPart r = rp.getDocumentPart(); if(r instanceof XSSFDrawing) { dg = (XSSFDrawing)r; continue; } addRelation(rp, sheetForNewWB); //This is a private method in XSSFWorkbook class so I copied this method over to this class } try { for(PackageRelationship pr : sheetFromOldWB.getPackagePart().getRelationships()) { if (pr.getTargetMode() == TargetMode.EXTERNAL) { sheetForNewWB.getPackagePart().addExternalRelationship (pr.getTargetURI().toASCIIString(), pr.getRelationshipType(), pr.getId()); } } } catch (InvalidFormatException e) { throw new POIXMLException("Failed to clone sheet", e); } OutputStream out = new ByteArrayOutputStream(); Method writeReflect = sheetFromOldWB.getClass(). getDeclaredMethod("write", OutputStream.class); //I had to use reflection here to get it to work because write(OutputStream os) is a private method in XSSFWorkbook class writeReflect.setAccessible(true); Object w = writeReflect.invoke(sheetFromOldWB,out); Method readReflect = sheetFromOldWB.getClass(). getDeclaredMethod("read", InputStream.class); //Same reason as above readReflect.setAccessible(true); Object r = readReflect.invoke(sheetForNewWB,new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray())); CTWorksheet ct = sheetForNewWB.getCTWorksheet(); if(ct.isSetLegacyDrawing()) { System.out.println("Cloning sheets with comments is not yet supported."); ct.unsetLegacyDrawing(); } if (ct.isSetPageSetup()) { System.out.println("Cloning sheets with page setup is not yet supported."); ct.unsetPageSetup(); } sheetForNewWB.setSelected(false); if (dg != null) { if(ct.isSetDrawing()) { ct.unsetDrawing(); } XSSFDrawing clonedDg = sheetForNewWB.createDrawingPatriarch(); clonedDg.getCTDrawing().set(dg.getCTDrawing()); clonedDg = sheetForNewWB.createDrawingPatriarch(); List<RelationPart> srcRels = sheetFromOldWB.createDrawingPatriarch().getRelationParts(); for (RelationPart rp : srcRels) { addRelation(rp, clonedDg); } } } FileOutputStream fileOut = new FileOutputStream("F:\\faraz\\Documents\\output.xlsx"); newWB.write(fileOut); oldWB.close(); newWB.close(); fileOut.close(); } private static void addRelation(RelationPart rp, POIXMLDocumentPart target) { PackageRelationship rel = rp.getRelationship(); if (rel.getTargetMode() == TargetMode.EXTERNAL) { target.getPackagePart().addRelationship( rel.getTargetURI(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId()); } else { XSSFRelation xssfRel = XSSFRelation.getInstance(rel.getRelationshipType()); if (xssfRel == null) { throw new POIXMLException("Can't clone sheet - unknown relation type found: "+rel.getRelationshipType()); } **target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart());** } } 

那双双星号的target.addRelation(rel.getId(), xssfRel, rp.getDocumentPart()); 给我一个麻烦 当我运行这个程序时,我得到这个错误:

 Exception in thread "main" java.lang.IllegalArgumentException: No part found for relationship id=rId1 - container=org.apache.poi.openxml4j.opc.ZipPackage@50c91c07 - relationshipType=http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable - source=/xl/worksheets/sheet1.xml - target=/xl/pivotTables/pivotTable1.xml,targetMode=INTERNAL at org.apache.poi.openxml4j.opc.PackagePart.getRelatedPart(PackagePart.java:487) at org.apache.poi.POIXMLDocumentPart.findExistingRelation(POIXMLDocumentPart.java:378) at org.apache.poi.POIXMLDocumentPart.addRelation(POIXMLDocumentPart.java:343) at oldmain.addRelation(oldmain.java:112) at oldmain.main(oldmain.java:50) 

现在正在寻找关系! 其实,我应该说我相信它在工作簿里面寻找关系,因为我不确定。 但是在那里找不到它们,因为我不是在同一个工作簿中克隆表单。

这是我真正的问题。 这里找什么? 我认为是正确的? 它实际上是在寻找工作簿内的一些关系吗? 如果我的想法是正确的,那么我需要将所有关系从源工作簿复制到新的工作簿。

有一件事,如果我只是说出这一行,那么这个方法就行了。 它会复制一切,但图表或图片不好看。 我的意思是,它会复制整数和string等,但图表,图片和图表将会丢失。 让我告诉你我的意思:

来源表格: 源表单

结果表: 结果表

来源表格: 源表单

结果表: 结果表

你看,这是有点但不完全。 我相信那是因为它缺less某种关系。 现在,我为什么要这样认识,是因为我在这条线内挖掘出来,看看它在呼唤什么,想要什么。

那么,是否有可能将所有关系从一个工作簿复制到另一个? 这实际上是我需要这个代码工作?

再次感谢,我将非常感激任何帮助。