2017-10-01 6 views
10

मेरे पास एक कार्यपुस्तिका है जिसमें इसमें कुछ डेटा है। मैं उस कार्यपुस्तिका को ले रहा हूं और अन्य कार्यपुस्तिका में डेटा के आधार पर इसमें एक लाइन चार्ट के साथ एक और कार्यपुस्तिका बना रहा हूं। कोड ठीक चलाता है, लेकिन जब भी मैं ग्राफ फ़ाइल खोलता हूं, मुझे चेतावनी We can't update some of the links in your workbook right now मिलती है। अगर मैं चेतावनी मेनू में Edit Links... बटन क्लिक करता हूं, तो यह दिखाता है कि डेटा कार्यपुस्तिका नहीं मिल सकती है। अगर मैं Change Source... पर क्लिक करता हूं, और उचित कार्यपुस्तिका का चयन करता हूं, तो यह ठीक काम करता है। ऐसा क्यों है? क्या पीओआई दो फाइलों के बीच लिंक बनाए रख सकता है?अपाचे पीओआई में मैं एक कार्यपुस्तिका को दूसरे से क्यों नहीं जोड़ सकता?

मेरे कोड:

डेटा कार्यपुस्तिका बनाने के लिए:

public static XSSFWorkbook createDataSpreadsheet(String name, long[] data) { 
    XSSFWorkbook workbook = new XSSFWorkbook(); 
    XSSFSheet sheet = workbook.createSheet(name); 

    int rowNumber = 0; 
    for(int i = 1; i < data.length + 1; i++) { 
     Row row = sheet.createRow(rowNumber++); 

     int columnNumber = 0; 
     row.createCell(columnNumber++).setCellValue(i); 
     row.createCell(columnNumber++).setCellValue(data[i - 1]); 
    } 

    return workbook; 
} 

ग्राफ कार्यपुस्तिका बनाने के लिए: XSSF में बाहरी लिंक का

public static XSSFWorkbook createLineChart(String name, XSSFWorkbook data) { 
    XSSFWorkbook workbook = new XSSFWorkbook(); 

    XSSFSheet sheet = workbook.createSheet(name); 

    XSSFDrawing drawing = sheet.createDrawingPatriarch(); 
    XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 15, 15); 
    XSSFChart lineChart = drawing.createChart(anchor); 

    XSSFChartLegend legend = lineChart.getOrCreateLegend(); 
    legend.setPosition(LegendPosition.BOTTOM); 

    LineChartData chartData = lineChart.getChartDataFactory().createLineChartData();  
    ChartAxis bottomAxis = lineChart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM); 
    ValueAxis leftAxis = lineChart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); 
    leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); 

    XSSFSheet dataSheet = data.getSheetAt(0); 
    ChartDataSource<Number> xData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 0, 0)); 
    ChartDataSource<Number> yData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 1, 1)); 

    LineChartSeries chartSeries = chartData.addSeries(xData, yData); 
    chartSeries.setTitle("A title"); 

    lineChart.plot(chartData, new ChartAxis[] { bottomAxis, leftAxis }); 

    return workbook; 
} 

उत्तर

5

निर्माण अच्छी तरह से अब तक लागू नहीं किया गया। ExternalLinksTable है लेकिन यदि आप Uses of this Class पर देखते हैं तो आप देखेंगे कि केवल उन बाहरी लिंक को पढ़ा गया है लेकिन बनाना और लिखना नहीं है।

इसलिए हमें निम्न स्तर की वस्तुओं के साथ काम करने की आवश्यकता है। और हमें Office OpenXML *.xlsx ज़िप-संग्रह के भीतर इस बाहरी लिंक की आंतरिक निर्भरताओं के बारे में ज्ञान चाहिए।

निम्न कार्य करता है जब तक कि दोनों कार्यपुस्तिकाएं उसी निर्देशिका में संग्रहीत की जाती हैं।

कोड मुख्य रूप से आपके प्रदान किए गए कोड को अन्य कार्यपुस्तिका में शीट के बाहरी लिंक बनाने के लिए विधि के साथ जोड़ा गया है। यह विधि निम्न स्तर की वस्तुओं का उपयोग कर रही है और यह बहुत सामान्य उपयोग नहीं है, लेकिन इसे सिद्धांत दिखाना चाहिए।

आपके कोड में अन्य परिवर्तन भी टिप्पणी की गई हैं।

import java.io.*; 

import org.apache.poi.ss.usermodel.*; 
import org.apache.poi.ss.usermodel.charts.*; 
import org.apache.poi.ss.util.CellRangeAddress; 

import org.apache.poi.xssf.usermodel.*; 
import org.apache.poi.xssf.model.ExternalLinksTable; 

import org.apache.poi.openxml4j.opc.*; 
import org.apache.poi.POIXMLDocumentPart; 

import org.openxmlformats.schemas.spreadsheetml.x2006.main.ExternalLinkDocument; 

import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; 

public class CreateExcelLineChartDataAnotherWorkbook { 

private static String datawbname = "DataWB.xlsx"; 
private static String chartwbname = "ChartWB.xlsx"; 

public CreateExcelLineChartDataAnotherWorkbook() throws Exception { 
    Workbook datawb = createDataSpreadsheet("ChartDataSheet"); 
    saveWorkbook(datawb, "/home/axel/Dokumente/"+datawbname); 

    Workbook chartwb = createLineChart("ChartSheet", (XSSFWorkbook)datawb); 
    saveWorkbook(chartwb, "/home/axel/Dokumente/"+chartwbname); 
} 

//your method only partially changed to have sample data 
public XSSFWorkbook createDataSpreadsheet(String name) { 
    Workbook workbook = new XSSFWorkbook(); 
    Sheet sheet = workbook.createSheet(name); 

    int rowNumber = 0; 
    for(int i = 0; i < 20; i++) { 
    Row row = sheet.createRow(rowNumber++); 

    int columnNumber = 0; 
    row.createCell(columnNumber++).setCellValue(Math.PI*i/10*2); 
    row.createCell(columnNumber++).setCellValue(Math.sin(Math.PI*i/10*2)); 
    } 

    return (XSSFWorkbook)workbook; 
} 

//method for saving the workbooks 
public void saveWorkbook(Workbook wb, String path) throws Exception { 
    wb.write(new FileOutputStream(path)); 
    wb.close(); 
} 

//your method changes are commented 
public XSSFWorkbook createLineChart(String name, XSSFWorkbook data) throws Exception { 
    Workbook workbook = new XSSFWorkbook(); 

    //create the external link to datawbname 
    int extwbid = 1; 
    createExternalLinkToWorksheet((XSSFWorkbook)workbook, datawbname, "ChartDataSheet", "rId"+extwbid); 

    Sheet sheet = workbook.createSheet(name); 

    Drawing drawing = sheet.createDrawingPatriarch(); 
    ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 15, 15); 
    Chart lineChart = drawing.createChart(anchor); 

    ChartLegend legend = lineChart.getOrCreateLegend(); 
    legend.setPosition(LegendPosition.BOTTOM); 

    LineChartData chartData = lineChart.getChartDataFactory().createLineChartData();  
    ChartAxis bottomAxis = lineChart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM); 
    ValueAxis leftAxis = lineChart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); 
    leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); 

    Sheet dataSheet = data.getSheetAt(0); 
    ChartDataSource<Number> xData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 0, 0)); 
    ChartDataSource<Number> yData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 1, 1)); 

    LineChartSeries chartSeries = chartData.addSeries(xData, yData); 
    chartSeries.setTitle("A title"); 

    lineChart.plot(chartData, new ChartAxis[] { bottomAxis, leftAxis }); 

    //since dataSheet is an external sheet, the formula in the org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef 
    //must be prefixed with [1], where 1 is the Id of the linked workbook 
    String catref = ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getCat().getNumRef().getF(); 
    ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getCat().getNumRef().setF("[" + extwbid + "]" + catref); 
    String valref = ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getVal().getNumRef().getF(); 
    ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getVal().getNumRef().setF("[" + extwbid + "]" + valref); 

    return (XSSFWorkbook)workbook; 
} 

//method for creating a external link to a sheet in another workbook 
public void createExternalLinkToWorksheet(XSSFWorkbook workbook, String wbname, String sheetname, String rIdExtWb) throws Exception { 
    OPCPackage opcpackage = workbook.getPackage(); 

    //creating /xl/externalLinks/externalLink1.xml having link to externalBook with external sheetName 
    PackagePartName partname = PackagingURIHelper.createPartName("/xl/externalLinks/externalLink1.xml"); 
    PackagePart part = opcpackage.createPart(partname, "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml"); 
    POIXMLDocumentPart externallinkstable = new POIXMLDocumentPart(part) { 
    @Override 
    protected void commit() throws IOException { 
    PackagePart part = getPackagePart(); 
    OutputStream out = part.getOutputStream(); 
    try { 
    ExternalLinkDocument doc = ExternalLinkDocument.Factory.parse(
     "<externalLink xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" 
    +"<externalBook xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\""+ rIdExtWb + "\">" 
    +"<sheetNames><sheetName val=\"" + sheetname + "\"/></sheetNames>" 
    +"</externalBook>" 
    +"</externalLink>" 
    ); 
    doc.save(out, DEFAULT_XML_OPTIONS); 
    out.close(); 
    } catch (Exception ex) { 
    ex.printStackTrace(); 
    }; 
    } 
    }; 
    //creating the relation to the external workbook in /xl/externalLinks/_rels/externalLink1.xml.rels 
    PackageRelationship packrelship = part.addRelationship(new java.net.URI(wbname), TargetMode.EXTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath", rIdExtWb); 

    //creating the relation to /xl/externalLinks/externalLink1.xml in /xl/_rels/workbook.xml.rels 
    String rIdExtLink = "rId" + (workbook.getRelationParts().size()+1); 
    workbook.addRelation(rIdExtLink, XSSFRelation.EXTERNAL_LINKS, externallinkstable); 

    //creating the <externalReferences><externalReference .../> in /xl/workbook.xml 
    workbook.getCTWorkbook().addNewExternalReferences().addNewExternalReference().setId(rIdExtLink); 

} 

public static void main(String[] args) throws Exception { 
    CreateExcelLineChartDataAnotherWorkbook mainObject = new CreateExcelLineChartDataAnotherWorkbook(); 
} 

} 

मेरा नया कोड एक क्लास MyXSSFWorkbook जो जुड़ा हुआ कार्यपुस्तिका और शीट के लिए ExternalLinksTable बनाने के लिए विधि द्वारा XSSFWorkbook फैली प्रदान करता है। यह कोड वास्तव में ExternalLinksTable बनाता है और यह ExternalLinksTable में ExternalLinksTable एस की सूची में जोड़ने के लिए प्रतिबिंब का उपयोग करता है। तो यह कार्यपुस्तिका का उपयोग कर आगे मिल जाएगा।

विधि केवल लिंक की गई कार्यपुस्तिका और लिंक्ड शीट के नामों की आवश्यकता है। यह आईडी स्वयं ही प्रबंधित करता है। यह ExternalLinksTable की आईडी (रिटर्न के रूप में /xl/externalLinks/externalLink1.xml में 1।, ताकि यह आईडी बाहरी कार्यपुस्तिका संदर्भ के रूप में सूत्रों में ([1]ChartDataSheet!$A$1:$A$20 में 1) के रूप में इस्तेमाल किया जा सकता।

import java.io.*; 

import org.apache.poi.ss.usermodel.*; 
import org.apache.poi.ss.usermodel.charts.*; 
import org.apache.poi.ss.util.CellRangeAddress; 

import org.apache.poi.xssf.usermodel.*; 
import org.apache.poi.xssf.model.ExternalLinksTable; 

import org.apache.poi.openxml4j.opc.*; 
import org.apache.poi.POIXMLDocumentPart; 

import org.openxmlformats.schemas.spreadsheetml.x2006.main.ExternalLinkDocument; 
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalReferences; 

import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; 

import java.lang.reflect.Field; 

import java.util.List; 
import java.util.ArrayList; 

public class CreateExcelLineChartExternalLinksTable { 

private static String datawbname = "DataWB.xlsx"; 
private static String chartwbname = "ChartWB.xlsx"; 

public CreateExcelLineChartExternalLinksTable() throws Exception { 
    Workbook datawb = createDataSpreadsheet("ChartDataSheet"); 
    saveWorkbook(datawb, "/home/axel/Dokumente/"+datawbname); 

    Workbook chartwb = createLineChart("ChartSheet", (XSSFWorkbook)datawb); 
    saveWorkbook(chartwb, "/home/axel/Dokumente/"+chartwbname); 
} 

//your method only partially changed to have sample data 
public XSSFWorkbook createDataSpreadsheet(String name) { 
    Workbook workbook = new XSSFWorkbook(); 
    Sheet sheet = workbook.createSheet(name); 

    int rowNumber = 0; 
    for(int i = 0; i < 20; i++) { 
    Row row = sheet.createRow(rowNumber++); 

    int columnNumber = 0; 
    row.createCell(columnNumber++).setCellValue(Math.PI*i/10*2); 
    row.createCell(columnNumber++).setCellValue(Math.sin(Math.PI*i/10*2)); 
    } 

    return (XSSFWorkbook)workbook; 
} 

//method for saving the workbooks 
public void saveWorkbook(Workbook wb, String path) throws Exception { 
    wb.write(new FileOutputStream(path)); 
    wb.close(); 
} 

//your method changes are commented 
public XSSFWorkbook createLineChart(String name, XSSFWorkbook data) throws Exception { 
    Workbook workbook = new MyXSSFWorkbook(); 

    Sheet sheet = workbook.createSheet(name); 

    Drawing drawing = sheet.createDrawingPatriarch(); 
    ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 15, 15); 
    Chart lineChart = drawing.createChart(anchor); 

    ChartLegend legend = lineChart.getOrCreateLegend(); 
    legend.setPosition(LegendPosition.BOTTOM); 

    LineChartData chartData = lineChart.getChartDataFactory().createLineChartData();  
    ChartAxis bottomAxis = lineChart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM); 
    ValueAxis leftAxis = lineChart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); 
    leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); 

    Sheet dataSheet = data.getSheetAt(0); 
    ChartDataSource<Number> xData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 0, 0)); 
    ChartDataSource<Number> yData = DataSources.fromNumericCellRange(dataSheet, new CellRangeAddress(0, dataSheet.getLastRowNum(), 1, 1)); 

    LineChartSeries chartSeries = chartData.addSeries(xData, yData); 
    chartSeries.setTitle("A title"); 

    lineChart.plot(chartData, new ChartAxis[] { bottomAxis, leftAxis }); 

    //create the ExternalLinksTable for the linked workbook and sheet 
    int extLinksId = ((MyXSSFWorkbook)workbook).createExternalLinksTableWbSheet(datawbname, "ChartDataSheet"); 
System.out.println(((XSSFWorkbook)workbook).getExternalLinksTable()); 

    //since dataSheet is an external sheet, the formula in the org.openxmlformats.schemas.drawingml.x2006.chart.CTNumRef 
    //must be prefixed with [1], where 1 is the Id of the linked workbook 
    String catref = ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getCat().getNumRef().getF(); 
    ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getCat().getNumRef().setF("["+extLinksId+"]" + catref); 
    String valref = ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getVal().getNumRef().getF(); 
    ((XSSFChart)lineChart).getCTChart().getPlotArea().getLineChartArray(0).getSerArray(0).getVal().getNumRef().setF("["+extLinksId+"]" + valref); 

    return (XSSFWorkbook)workbook; 
} 

public static void main(String[] args) throws Exception { 
    CreateExcelLineChartExternalLinksTable mainObject = new CreateExcelLineChartExternalLinksTable(); 
} 

//class which extends XSSFWorkbook and provides a method for creating ExternalLinksTable for linked workbook and sheet 
private class MyXSSFWorkbook extends XSSFWorkbook { 

    //method for creating ExternalLinksTable for linked workbook and sheet 
    //returns the Id of this ExternalLinksTable 
    int createExternalLinksTableWbSheet(String wbname, String sheetname) throws Exception { 

    List<ExternalLinksTable> elternallinkstablelist = getExternalLinksTable(); 
    int extLinksId = 1; 
    if (elternallinkstablelist != null) extLinksId = elternallinkstablelist.size()+1; 

    OPCPackage opcpackage = getPackage(); 

    //creating /xl/externalLinks/externalLink1.xml having link to externalBook with external sheetName 
    PackagePartName partname = PackagingURIHelper.createPartName("/xl/externalLinks/externalLink"+extLinksId+".xml"); 
    PackagePart part = opcpackage.createPart(partname, "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml"); 

    OutputStream out = part.getOutputStream(); 
    ExternalLinkDocument doc = ExternalLinkDocument.Factory.parse(
    "<externalLink xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">" 
    +"<externalBook xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"rId1\">" 
    +"<sheetNames><sheetName val=\"" + sheetname + "\"/></sheetNames>" 
    +"</externalBook>" 
    +"</externalLink>" 
    ); 
    doc.save(out, DEFAULT_XML_OPTIONS); 
    out.close(); 

    //creating the relation to the external workbook in /xl/externalLinks/_rels/externalLink1.xml.rels 
    PackageRelationship packrelship = part.addRelationship(new java.net.URI(wbname), TargetMode.EXTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath", "rId1"); 

    ExternalLinksTable externallinkstable = new ExternalLinksTable(part); 

    //creating the relation to /xl/externalLinks/externalLink1.xml in /xl/_rels/workbook.xml.rels 
    String rIdExtLink = "rId" + (getRelationParts().size()+1); 
    addRelation(rIdExtLink, XSSFRelation.EXTERNAL_LINKS, externallinkstable); 

    //creating the <externalReferences><externalReference .../> in /xl/workbook.xml 
    CTExternalReferences externalreferences = getCTWorkbook().getExternalReferences(); 
    if (externalreferences == null) externalreferences = getCTWorkbook().addNewExternalReferences(); 
    externalreferences.addNewExternalReference().setId(rIdExtLink); 

    Field externalLinksField = XSSFWorkbook.class.getDeclaredField("externalLinks"); 
    externalLinksField.setAccessible(true); 
    @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs 
    List<ExternalLinksTable> externalLinks = (ArrayList<ExternalLinksTable>)externalLinksField.get(this); 
    if (externalLinks == null) { 
    externalLinks = new ArrayList<ExternalLinksTable>(); 
    externalLinks.add(externallinkstable); 
    externalLinksField.set(this, externalLinks); 
    } else { 
    externalLinks.add(externallinkstable); 
    } 

    return extLinksId; 
    } 
} 
} 
+0

अच्छा जवाब। यह काम करता है, लेकिन मैं इंतज़ार कर रहा हूँ यह देखने के लिए कि क्या कोई ऐसा समाधान पोस्ट करता है जो सरल और अधिक पोर्टेबल/लचीला है। जैसा कि आपने अपने उत्तर में कहा है, यह बहुत कम स्तर है और आमतौर पर प्रयोग योग्य नहीं है। –

+0

@Alex Quilliam: मैंने नया कोड प्रदान किया है जो अधिक सामान्य उपयोग योग्य है। –

संबंधित मुद्दे