Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 将所有类型的关系从一个工作簿复制到新工作簿Apache POI XSSF工作簿_Java_Excel_Apache Poi - Fatal编程技术网

Java 将所有类型的关系从一个工作簿复制到新工作簿Apache POI XSSF工作簿

Java 将所有类型的关系从一个工作簿复制到新工作簿Apache POI XSSF工作簿,java,excel,apache-poi,Java,Excel,Apache Poi,我一直试图从一个工作簿中提取关系,并将它们复制到另一个新创建的工作簿中。 到目前为止,我已经尝试过: XSSFWorkbook oldWB = new XSSFWorkbook(new File("F:\\pivottablesurvey.xlsx")); //src workbook XSSFWorkbook newWB = new XSSFWorkbook(); //target workbook POIXMLDocument upcastOldwb = oldWB; //Upcastin

我一直试图从一个工作簿中提取关系,并将它们复制到另一个新创建的工作簿中。 到目前为止,我已经尝试过:

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
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)
首先,我承认我甚至不知道我所采取的方法是否正确。我只是尝试将关系从一个工作簿复制到另一个工作簿。 任何帮助都将不胜感激

谢谢

编辑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:

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

事实证明,我实现了这个建议,我的实现与在SO和coderanch上找到的其他解决方案99%相同。但这一解决方案存在一个问题。如果工作表包含表格、图片、图表等,那么这些解决方案就不能很好地工作

然后我想到了一个聪明的方法将工作表复制到新工作簿中:这个解决方案是其他解决方案中最好的。它保持一切完好无损,没有任何图形、图表、图片会断裂。但正如你所知道的,这是一种令人讨厌的方式。不是很酷的方式。所以我想实现一些正确的方法。或者以专业开发人员的方式

为此,我研究了
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());**
}
}
在这一点上,它正在寻找关系!实际上,我应该说我相信它是在工作簿中寻找关系的,因为我不确定。但它无法在那里找到它们,因为我没有在同一工作簿中克隆工作表

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

有一件事,如果我只是注释掉那一行,那么这个方法就可以了。它会复制所有的东西,但是图形或图片看起来不好。我的意思是,它会复制整数和字符串等,但图形、图片和图表会丢失。让我告诉你我的意思:

来源表:

结果表:

来源表:

结果表:

你看,它在某种程度上起作用了,但还没有完全发挥作用。我相信这是因为它缺少了某种关系。现在,我之所以意识到这一点,是因为我在那条线里面挖掘,看看它在呼唤什么,它想要什么

那么,是否可以将所有关系从一个工作簿复制到另一个工作簿?这真的是我工作所需要的吗


再次感谢您,我将非常感谢您的帮助

你想复制什么样的关系,为什么?大多数都是内置的excel链接,例如工作簿到工作表,因此您不希望复制,因为POI会在您添加/删除工作表时处理这些问题。对于我来说,复制整个工作簿,然后删除所有不需要的工作表是一种正确的方法。这个应该是什么“黑客”?尝试创建一个新工作簿,然后将工作表从另一个工作簿克隆到另一个工作簿中,在我看来,这似乎是一种“黑客”方式,因为您已经看到工作表与工作簿的连接有多么紧密。在您可以为某个零件添加关系之前,该零件必须存在。我看不出复制其他部分的任何逻辑,你错过了吗?如果你想要轻松的生活,只需复制Excel文件并使用Apache POI删除你不想要的工作表。如果你真的想在这个非常低的层次上乱搞,你必须花一些时间阅读关于XLSX格式和OPC格式的Microsoft文件格式文档,你的问题可能不仅仅是POI API,更多的是理解文件格式是如何工作的……你想复制什么样的关系,为什么?大多数都是内置的excel链接,例如工作簿到工作表,因此您不希望复制,因为POI会在您添加/删除工作表时处理这些问题。对于我来说,复制整个工作簿,然后删除所有不需要的工作表是一种正确的方法。这个应该是什么“黑客”?尝试创建一个新工作簿,然后将工作表从另一个工作簿克隆到另一个工作簿中,在我看来,这似乎是一种“黑客”方式,因为您已经看到工作表与工作簿的连接有多么紧密。在您可以为某个零件添加关系之前,该零件必须存在。我看不出复制其他部分的任何逻辑,你错过了吗?如果你想要轻松的生活,只需复制Excel文件并使用Apache POI删除你不想要的工作表。如果你真的想在这个非常低的层次上乱搞,你必须花一些时间阅读关于XLSX格式和OPC格式的Microsoft文件格式文档,你的问题可能不仅仅是POI API,更多的是理解文件格式是如何工作的。。。