mirror of https://github.com/apache/poi.git
Bugzilla 52576: support changing external file references in HSSFWorkbook
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1242701 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c8e2fe7f5e
commit
a3a8dcf335
|
@ -34,6 +34,8 @@
|
||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.8-beta6" date="2012-??-??">
|
<release version="3.8-beta6" date="2012-??-??">
|
||||||
|
<action dev="poi-developers" type="add">52576 - support changing external file references in HSSFWorkbook</action>
|
||||||
|
<action dev="poi-developers" type="add">49896 - support external references in FormulaRenderer</action>
|
||||||
<action dev="poi-developers" type="fix">52527 - avoid exception when matching shared formula records in HSSF</action>
|
<action dev="poi-developers" type="fix">52527 - avoid exception when matching shared formula records in HSSF</action>
|
||||||
<action dev="poi-developers" type="add">52568 - Added methods to set/get an XWPFRun's text color</action>
|
<action dev="poi-developers" type="add">52568 - Added methods to set/get an XWPFRun's text color</action>
|
||||||
<action dev="poi-developers" type="add">52566 - Added methods to set/get vertical alignment and color in XWPFTableCell</action>
|
<action dev="poi-developers" type="add">52566 - Added methods to set/get vertical alignment and color in XWPFTableCell</action>
|
||||||
|
|
|
@ -2457,4 +2457,18 @@ public final class InternalWorkbook {
|
||||||
}
|
}
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes an external referenced file to another file.
|
||||||
|
* A formular in Excel which refers a cell in another file is saved in two parts:
|
||||||
|
* The referenced file is stored in an reference table. the row/cell information is saved separate.
|
||||||
|
* This method invokation will only change the reference in the lookup-table itself.
|
||||||
|
* @param oldUrl The old URL to search for and which is to be replaced
|
||||||
|
* @param newUrl The URL replacement
|
||||||
|
* @return true if the oldUrl was found and replaced with newUrl. Otherwise false
|
||||||
|
*/
|
||||||
|
public boolean changeExternalReference(String oldUrl, String newUrl) {
|
||||||
|
return linkTable.changeExternalReference(oldUrl, newUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,4 +552,27 @@ final class LinkTable {
|
||||||
private int findRefIndexFromExtBookIndex(int extBookIndex) {
|
private int findRefIndexFromExtBookIndex(int extBookIndex) {
|
||||||
return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex);
|
return _externSheetRecord.findRefIndexFromExtBookIndex(extBookIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes an external referenced file to another file.
|
||||||
|
* A formular in Excel which refers a cell in another file is saved in two parts:
|
||||||
|
* The referenced file is stored in an reference table. the row/cell information is saved separate.
|
||||||
|
* This method invokation will only change the reference in the lookup-table itself.
|
||||||
|
* @param oldUrl The old URL to search for and which is to be replaced
|
||||||
|
* @param newUrl The URL replacement
|
||||||
|
* @return true if the oldUrl was found and replaced with newUrl. Otherwise false
|
||||||
|
*/
|
||||||
|
public boolean changeExternalReference(String oldUrl, String newUrl) {
|
||||||
|
for(ExternalBookBlock ex : _externalBookBlocks) {
|
||||||
|
SupBookRecord externalRecord = ex.getExternalBookRecord();
|
||||||
|
if (externalRecord.isExternalReferences()
|
||||||
|
&& externalRecord.getURL().equals(oldUrl)) {
|
||||||
|
|
||||||
|
externalRecord.setURL(newUrl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +33,8 @@ import org.apache.poi.util.StringUtil;
|
||||||
*/
|
*/
|
||||||
public final class SupBookRecord extends StandardRecord {
|
public final class SupBookRecord extends StandardRecord {
|
||||||
|
|
||||||
|
private final static POILogger logger = POILogFactory.getLogger(SupBookRecord.class);
|
||||||
|
|
||||||
public final static short sid = 0x01AE;
|
public final static short sid = 0x01AE;
|
||||||
|
|
||||||
private static final short SMALL_RECORD_SIZE = 4;
|
private static final short SMALL_RECORD_SIZE = 4;
|
||||||
|
@ -42,6 +46,15 @@ public final class SupBookRecord extends StandardRecord {
|
||||||
private String[] field_3_sheet_names;
|
private String[] field_3_sheet_names;
|
||||||
private boolean _isAddInFunctions;
|
private boolean _isAddInFunctions;
|
||||||
|
|
||||||
|
protected static final char CH_VOLUME = 1;
|
||||||
|
protected static final char CH_SAME_VOLUME = 2;
|
||||||
|
protected static final char CH_DOWN_DIR = 3;
|
||||||
|
protected static final char CH_UP_DIR = 4;
|
||||||
|
protected static final char CH_LONG_VOLUME = 5;
|
||||||
|
protected static final char CH_STARTUP_DIR = 6;
|
||||||
|
protected static final char CH_ALT_STARTUP_DIR = 7;
|
||||||
|
protected static final char CH_LIB_DIR = 8;
|
||||||
|
protected static final String PATH_SEPERATOR = System.getProperty("file.separator");
|
||||||
|
|
||||||
public static SupBookRecord createInternalReferences(short numberOfSheets) {
|
public static SupBookRecord createInternalReferences(short numberOfSheets) {
|
||||||
return new SupBookRecord(false, numberOfSheets);
|
return new SupBookRecord(false, numberOfSheets);
|
||||||
|
@ -192,21 +205,51 @@ public final class SupBookRecord extends StandardRecord {
|
||||||
return encodedUrl;
|
return encodedUrl;
|
||||||
}
|
}
|
||||||
private static String decodeFileName(String encodedUrl) {
|
private static String decodeFileName(String encodedUrl) {
|
||||||
return encodedUrl.substring(1);
|
/* see "MICROSOFT OFFICE EXCEL 97-2007 BINARY FILE FORMAT SPECIFICATION" */
|
||||||
// TODO the following special characters may appear in the rest of the string, and need to get interpreted
|
StringBuilder sb = new StringBuilder();
|
||||||
/* see "MICROSOFT OFFICE EXCEL 97-2007 BINARY FILE FORMAT SPECIFICATION"
|
for(int i=1; i<encodedUrl.length(); i++) {
|
||||||
chVolume 1
|
char c = encodedUrl.charAt(i);
|
||||||
chSameVolume 2
|
switch (c) {
|
||||||
chDownDir 3
|
case CH_VOLUME:
|
||||||
chUpDir 4
|
char driveLetter = encodedUrl.charAt(++i);
|
||||||
chLongVolume 5
|
if (driveLetter == '@') {
|
||||||
chStartupDir 6
|
sb.append("\\\\");
|
||||||
chAltStartupDir 7
|
} else {
|
||||||
chLibDir 8
|
//Windows notation for drive letters
|
||||||
|
sb.append(driveLetter).append(":");
|
||||||
*/
|
}
|
||||||
|
break;
|
||||||
|
case CH_SAME_VOLUME:
|
||||||
|
sb.append(PATH_SEPERATOR);
|
||||||
|
break;
|
||||||
|
case CH_DOWN_DIR:
|
||||||
|
sb.append(PATH_SEPERATOR);
|
||||||
|
break;
|
||||||
|
case CH_UP_DIR:
|
||||||
|
sb.append("..").append(PATH_SEPERATOR);
|
||||||
|
break;
|
||||||
|
case CH_LONG_VOLUME:
|
||||||
|
//Don't known to handle...
|
||||||
|
logger.log(POILogger.WARN, "Found unexpected key: ChLongVolume - IGNORING");
|
||||||
|
break;
|
||||||
|
case CH_STARTUP_DIR:
|
||||||
|
case CH_ALT_STARTUP_DIR:
|
||||||
|
case CH_LIB_DIR:
|
||||||
|
logger.log(POILogger.WARN, "EXCEL.EXE path unkown - using this directoy instead: .");
|
||||||
|
sb.append(".").append(PATH_SEPERATOR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
public String[] getSheetNames() {
|
public String[] getSheetNames() {
|
||||||
return field_3_sheet_names.clone();
|
return field_3_sheet_names.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setURL(String pUrl) {
|
||||||
|
//Keep the first marker character!
|
||||||
|
field_2_encoded_url = field_2_encoded_url.substring(0, 1) + pUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1798,5 +1798,16 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
|
||||||
return recalc != null && recalc.getEngineId() != 0;
|
return recalc != null && recalc.getEngineId() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes an external referenced file to another file.
|
||||||
|
* A formular in Excel which refers a cell in another file is saved in two parts:
|
||||||
|
* The referenced file is stored in an reference table. the row/cell information is saved separate.
|
||||||
|
* This method invokation will only change the reference in the lookup-table itself.
|
||||||
|
* @param oldUrl The old URL to search for and which is to be replaced
|
||||||
|
* @param newUrl The URL replacement
|
||||||
|
* @return true if the oldUrl was found and replaced with newUrl. Otherwise false
|
||||||
|
*/
|
||||||
|
public boolean changeExternalReference(String oldUrl, String newUrl) {
|
||||||
|
return workbook.changeExternalReference(oldUrl, newUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import static org.apache.poi.hssf.record.SupBookRecord.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the serialization and deserialization of the SupBook record
|
* Tests the serialization and deserialization of the SupBook record
|
||||||
* class works correctly.
|
* class works correctly.
|
||||||
|
@ -110,4 +112,46 @@ public final class TestSupBookRecord extends TestCase {
|
||||||
assertTrue(record.isAddInFunctions());
|
assertTrue(record.isAddInFunctions());
|
||||||
TestcaseRecordInputStream.confirmRecordEncoding(0x01AE, dataAIF, record.serialize());
|
TestcaseRecordInputStream.confirmRecordEncoding(0x01AE, dataAIF, record.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testExternalReferenceUrl() {
|
||||||
|
String[] sheetNames = new String[]{"SampleSheet"};
|
||||||
|
final char startMarker = (char)1;
|
||||||
|
|
||||||
|
SupBookRecord record;
|
||||||
|
|
||||||
|
record = new SupBookRecord(startMarker + "test.xls", sheetNames);
|
||||||
|
assertEquals("test.xls", record.getURL());
|
||||||
|
|
||||||
|
//UNC path notation
|
||||||
|
record = new SupBookRecord(startMarker + "" + CH_VOLUME + "@servername" + CH_DOWN_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals("\\\\servername" + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Absolute path notation - different device
|
||||||
|
record = new SupBookRecord(startMarker + "" + CH_VOLUME + "D" + CH_DOWN_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals("D:" + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Absolute path notation - same device
|
||||||
|
record = new SupBookRecord(startMarker + "" + CH_SAME_VOLUME + "folder" + CH_DOWN_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals(PATH_SEPERATOR + "folder" + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Relative path notation - down
|
||||||
|
record = new SupBookRecord(startMarker + "folder" + CH_DOWN_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals("folder" + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Relative path notation - up
|
||||||
|
record = new SupBookRecord(startMarker +""+ CH_UP_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals(".." + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Relative path notation - for EXCEL.exe - fallback
|
||||||
|
record = new SupBookRecord(startMarker +""+ CH_STARTUP_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals("." + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Relative path notation - for EXCEL lib folder - fallback
|
||||||
|
record = new SupBookRecord(startMarker +""+ CH_LIB_DIR + "test.xls", sheetNames);
|
||||||
|
assertEquals("." + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
|
||||||
|
//Relative path notation - for alternative EXCEL.exe - fallback
|
||||||
|
record = new SupBookRecord(startMarker +""+ CH_ALT_STARTUP_DIR+ "test.xls", sheetNames);
|
||||||
|
assertEquals("." + PATH_SEPERATOR + "test.xls", record.getURL());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1678,17 +1678,17 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
||||||
|
|
||||||
row = s.getRow(4);
|
row = s.getRow(4);
|
||||||
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
||||||
assertEquals("'[\u0005$http://gagravarr.org/FormulaRefs.xls]Sheet1'!B1", row.getCell(1).getCellFormula());
|
assertEquals("'[$http://gagravarr.org/FormulaRefs.xls]Sheet1'!B1", row.getCell(1).getCellFormula());
|
||||||
assertEquals(112.0, row.getCell(1).getNumericCellValue());
|
assertEquals(112.0, row.getCell(1).getNumericCellValue());
|
||||||
|
|
||||||
// Change 4
|
// Change 4
|
||||||
row.getCell(1).setCellFormula("'[\u0005$http://gagravarr.org/FormulaRefs2.xls]Sheet1'!B2");
|
row.getCell(1).setCellFormula("'[$http://gagravarr.org/FormulaRefs2.xls]Sheet1'!B2");
|
||||||
row.getCell(1).setCellValue(123.0);
|
row.getCell(1).setCellValue(123.0);
|
||||||
|
|
||||||
// Add 5
|
// Add 5
|
||||||
row = s.createRow(5);
|
row = s.createRow(5);
|
||||||
row.createCell(1, Cell.CELL_TYPE_FORMULA);
|
row.createCell(1, Cell.CELL_TYPE_FORMULA);
|
||||||
row.getCell(1).setCellFormula("'[\u0005$http://example.com/FormulaRefs.xls]Sheet1'!B1");
|
row.getCell(1).setCellFormula("'[$http://example.com/FormulaRefs.xls]Sheet1'!B1");
|
||||||
row.getCell(1).setCellValue(234.0);
|
row.getCell(1).setCellValue(234.0);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1719,12 +1719,12 @@ public final class TestBugs extends BaseTestBugzillaIssues {
|
||||||
if(1==2) {
|
if(1==2) {
|
||||||
row = s.getRow(4);
|
row = s.getRow(4);
|
||||||
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
||||||
assertEquals("'[\u0005$http://gagravarr.org/FormulaRefs2.xls]Sheet1'!B2", row.getCell(1).getCellFormula());
|
assertEquals("'[$http://gagravarr.org/FormulaRefs2.xls]Sheet1'!B2", row.getCell(1).getCellFormula());
|
||||||
assertEquals(123.0, row.getCell(1).getNumericCellValue());
|
assertEquals(123.0, row.getCell(1).getNumericCellValue());
|
||||||
|
|
||||||
row = s.getRow(5);
|
row = s.getRow(5);
|
||||||
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
assertEquals(Cell.CELL_TYPE_FORMULA, row.getCell(1).getCellType());
|
||||||
assertEquals("'[\u0005$http://example.com/FormulaRefs.xls]Sheet1'!B1", row.getCell(1).getCellFormula());
|
assertEquals("'[$http://example.com/FormulaRefs.xls]Sheet1'!B1", row.getCell(1).getCellFormula());
|
||||||
assertEquals(234.0, row.getCell(1).getNumericCellValue());
|
assertEquals(234.0, row.getCell(1).getNumericCellValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2193,4 +2193,12 @@ if(1==2) {
|
||||||
// Good
|
// Good
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void test49896() {
|
||||||
|
HSSFWorkbook wb = openSample("49896.xls");
|
||||||
|
HSSFCell cell = wb.getSheetAt(0).getRow(1).getCell(1);
|
||||||
|
assertEquals("VLOOKUP(A2,'[C:Documents and Settings/Yegor/My Documents/csco.xls]Sheet1'!$A$2:$B$3,2,FALSE)",
|
||||||
|
cell.getCellFormula());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class TestExternalReferenceChange extends TestCase {
|
||||||
|
|
||||||
|
private static final String MAIN_WORKBOOK_FILENAME = "52575_main.xls";
|
||||||
|
private static final String SOURCE_DUMMY_WORKBOOK_FILENAME = "source_dummy.xls";
|
||||||
|
private static final String SOURCE_WORKBOOK_FILENAME = "52575_source.xls";
|
||||||
|
|
||||||
|
private HSSFWorkbook mainWorkbook;
|
||||||
|
private HSSFWorkbook sourceWorkbook;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
mainWorkbook = HSSFTestDataSamples.openSampleWorkbook(MAIN_WORKBOOK_FILENAME);
|
||||||
|
sourceWorkbook = HSSFTestDataSamples.openSampleWorkbook(SOURCE_WORKBOOK_FILENAME);
|
||||||
|
|
||||||
|
assertNotNull(mainWorkbook);
|
||||||
|
assertNotNull(sourceWorkbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDummyToSource() throws IOException {
|
||||||
|
boolean changed = mainWorkbook.changeExternalReference("DOESNOTEXIST", SOURCE_WORKBOOK_FILENAME);
|
||||||
|
assertFalse(changed);
|
||||||
|
|
||||||
|
changed = mainWorkbook.changeExternalReference(SOURCE_DUMMY_WORKBOOK_FILENAME, SOURCE_WORKBOOK_FILENAME);
|
||||||
|
assertTrue(changed);
|
||||||
|
|
||||||
|
HSSFSheet lSheet = mainWorkbook.getSheetAt(0);
|
||||||
|
HSSFCell lA1Cell = lSheet.getRow(0).getCell(0);
|
||||||
|
|
||||||
|
assertEquals(Cell.CELL_TYPE_FORMULA, lA1Cell.getCellType());
|
||||||
|
|
||||||
|
HSSFFormulaEvaluator lMainWorkbookEvaluator = new HSSFFormulaEvaluator(mainWorkbook);
|
||||||
|
HSSFFormulaEvaluator lSourceEvaluator = new HSSFFormulaEvaluator(sourceWorkbook);
|
||||||
|
HSSFFormulaEvaluator.setupEnvironment(
|
||||||
|
new String[]{MAIN_WORKBOOK_FILENAME, SOURCE_WORKBOOK_FILENAME},
|
||||||
|
new HSSFFormulaEvaluator[] {lMainWorkbookEvaluator, lSourceEvaluator});
|
||||||
|
|
||||||
|
assertEquals(Cell.CELL_TYPE_NUMERIC, lMainWorkbookEvaluator.evaluateFormulaCell(lA1Cell));
|
||||||
|
|
||||||
|
assertEquals(20.0d, lA1Cell.getNumericCellValue(), 0.00001d);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -32,8 +32,6 @@ public class TestMissingWorkbook extends TestCase {
|
||||||
private static final String SOURCE_DUMMY_WORKBOOK_FILENAME = "source_dummy.xls";
|
private static final String SOURCE_DUMMY_WORKBOOK_FILENAME = "source_dummy.xls";
|
||||||
private static final String SOURCE_WORKBOOK_FILENAME = "52575_source.xls";
|
private static final String SOURCE_WORKBOOK_FILENAME = "52575_source.xls";
|
||||||
|
|
||||||
private static final String propertyKey = WorkbookEvaluator.class.getName() + ".IGNORE_MISSING_WORKBOOKS";
|
|
||||||
|
|
||||||
private HSSFWorkbook mainWorkbook;
|
private HSSFWorkbook mainWorkbook;
|
||||||
private HSSFWorkbook sourceWorkbook;
|
private HSSFWorkbook sourceWorkbook;
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue