In our project, we have different versions of excelsheets which reference each other:
C:\V1\Sample.xls //no references
C:\V2\Sample.xls //references V1
C:\V3\Sample.xls //references V2
Example of a cell value:
=MID('C:\V1\[Sample.xls]Sheet1'!$AB2;21;1)
Now I want to evaluate formulas of V3 using apache POI, I found the following example here
// Create a FormulaEvaluator to use
FormulaEvaluator mainWorkbookEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
// Track the workbook references
Map<String,FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>();
// Add this workbook
workbooks.put("report.xlsx", mainWorkbookEvaluator);
// Add two others
workbooks.put("input.xls", WorkbookFactory.create("c:\temp\input22.xls").getCreationHelper().createFormulaEvaluator());
workbooks.put("lookups.xlsx", WorkbookFactory.create("/home/poi/data/tmp-lookups.xlsx").getCreationHelper().createFormulaEvaluator());
// Attach them
mainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);
// Evaluate
mainWorkbookEvaluator.evaluateAll();
Now my problem: I do not know the locations of the files, I therefore need to get all references from the mainworkbook and then automatically (and probably recursively) add them, not static like in the example above. Is there a function to get the references or does anyone know a way to achieve this?
Additionally, I am wondering if I have to add all FormulaEvaluator to V3 or do I have to add V2 to V3 and V1 to V2 for this to work?
I currently have setIgnoreMissingWorkbooks(true) implemented, but as the values will change and we do not want to open each excel file manually to update the references I want to implement this solution. Any help is appreciated
To get all external references use following method:
private static Set<String> getReferencedWorkbooks(Workbook workbook) {
Set<String> workbookNames = new HashSet<>();
final EvaluationWorkbook evalWorkbook;
if (workbook instanceof HSSFWorkbook) {
evalWorkbook = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
} else if (workbook instanceof XSSFWorkbook) {
evalWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
} else {
throw new IllegalStateException();
}
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
Sheet sheet = workbook.getSheetAt(i);
final EvaluationSheet evalSheet = evalWorkbook.getSheet(i);
for (Row r : sheet) {
for (Cell c : r) {
if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
final EvaluationCell cell = evalSheet.getCell(c.getRowIndex(), c.getColumnIndex());
final Ptg[] formulaTokens = evalWorkbook.getFormulaTokens(cell);
for (Ptg formulaToken : formulaTokens) {
final int externalSheetIndex;
if (formulaToken instanceof Ref3DPtg) {
Ref3DPtg refToken = (Ref3DPtg) formulaToken;
externalSheetIndex = refToken.getExternSheetIndex();
} else if (formulaToken instanceof Ref3DPxg) {
Ref3DPxg refToken = (Ref3DPxg) formulaToken;
externalSheetIndex = refToken.getExternalWorkbookNumber();
} else {
externalSheetIndex = -1;
}
if (externalSheetIndex >= 0) {
final ExternalSheet externalSheet = evalWorkbook.getExternalSheet(externalSheetIndex);
workbookNames.add(externalSheet.getWorkbookName());
}
}
}
}
}
}
return workbookNames;
}
If your all of your workbooks are XLSX/XLSM you can use following code:
private static Set<String> getReferencedWorkbooksXssf(XSSFWorkbook workbook) {
Set<String> workbookNames = new HashSet<>();
final List<ExternalLinksTable> externalLinksTable = workbook.getExternalLinksTable();
for (ExternalLinksTable linksTable : externalLinksTable) {
final String linkedFileName = linksTable.getLinkedFileName();
workbookNames.add(linkedFileName);
}
return workbookNames;
}
Related
I have this code and this error constantly is appearing. I have only one excel , but nothing seems to work, I already tried a lot of option that I found surfing on internet, but nothing seems to work according of what I want to do.
I use different case to make easier the logical of my business and I am not going to change that, so I am not sure how to do solve this issue.
private static final String nombreArchivo = "casoPrueba.xlsx";
private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;
public static XSSFSheet SacaHojaSegunTipo(String tipo) throws IOException {
if (workbook == null) {
try (FileInputStream fis = new FileInputStream(new File(rutaArchivo))) {
workbook = new XSSFWorkbook(fis);
}
}
XSSFSheet spreadsheet = null;
switch (tipo) {
case "Candidatos Minorista":
spreadsheet = workbook.getSheetAt(1);
break;
case "Conversion Candidatos":
spreadsheet = workbook.getSheetAt(2);
break;
case "Cuentas":
spreadsheet = workbook.getSheetAt(3);
break;
case "Detalle Cuenta":
spreadsheet = workbook.getSheetAt(4);
break;
case "Historial de Cuentas":
spreadsheet = workbook.getSheetAt(5);
break;
case "Cuentas Financieras":
spreadsheet = workbook.getSheetAt(6);
break;
case "AR Estado Automático":
spreadsheet = workbook.getSheetAt(7);
break;
case "Oportunidades":
spreadsheet = workbook.getSheetAt(8);
break;
default:
spreadsheet = workbook.getSheetAt(0);
break;
}
return spreadsheet;
}
I know this is not a efficient method.Hope anyone can help me with this.
Something like this (I tried to change your code as little as possible, so it's not perfect)
private static final String nombreArchivo = "casoPrueba.xlsx";
private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;
private static XSSFWorkbook workbook = null;
public static XSSFSheet SacaHojaSegunTipo(String tipo) throws IOException {
if (workbook == null) {
try (FileInputStream fis = new FileInputStream(new File(rutaArchivo))) {
workbook = new XSSFWorkbook(fis);
}
}
XSSFSheet spreadsheet = null;
switch (tipo) {
case "Candidatos Minorista":
spreadsheet = workbook.getSheetAt(1);
break;
case "Conversion Candidatos":
spreadsheet = workbook.getSheetAt(2);
break;
case "Cuentas":
spreadsheet = workbook.getSheetAt(3);
break;
case "Detalle Cuenta":
spreadsheet = workbook.getSheetAt(4);
break;
case "Historial de Cuentas":
spreadsheet = workbook.getSheetAt(5);
break;
case "Navegar Cuentas":
spreadsheet = workbook.getSheetAt(6);
break;
case "Validar Número Operación":
spreadsheet = workbook.getSheetAt(7);
break;
case "Validar Tipos de Productos":
spreadsheet = workbook.getSheetAt(8);
break;
case "Validar Referencia y Cód. Auto.":
spreadsheet = workbook.getSheetAt(9);
break;
default:
spreadsheet = workbook.getSheetAt(0);
}
return spreadsheet;
}
First, a quick aside : it's worth noting the following from
https://poi.apache.org/apidocs/dev/org/apache/poi/xssf/usermodel/XSSFWorkbook.html#XSSFWorkbook-java.io.InputStream-
Using an InputStream requires more memory than using a File, so if a
File is available then you should instead do something like
OPCPackage pkg = OPCPackage.open(path);
XSSFWorkbook wb = new XSSFWorkbook(pkg);
// work with the wb object
......
pkg.close(); // gracefully closes the underlying zip file
(although doing wb.close() also closes the files and streams).
Now, your core issue is that you need to release resources after the sheet or workbook are no longer required, but at present you cannot do so since these are hidden local inside the method.
So you need to give your caller access to close them when it's done. It's a matter of preference, but personally I would prefer encapsulating the spreadsheet into it's own class - a spreadsheet IS a clearly defined object in its own right, after all ! As such, this would necessitate a change from static, so something like :
public class RutaArchivo implements AutoCloseable {
private static final String nombreArchivo = "casoPrueba.xlsx";
private static final String rutaArchivo = "src\\test\\resources\\data\\" + nombreArchivo;
public static final String CANDIDATOS_MINORISTA = "Candidatos Minorista";
public static final String CONVERSION_CANDIDATOS = "Conversion Candidatos"
public static final String CUENTAS = "Cuentas";
private XSSFWorkbook workbook;
public RutaArchivo() throws InvalidFormatException, IOException {
workbook = new XSSFWorkbook(new File(rutaArchivo));
}
#Override
public void close() throws Exception {
if (workbook != null) {
workbook.close();
workbook = null;
}
}
public XSSFSheet sacaHojaSegunTipo(String tipo) {
if (workbook == null) {
throw new IllegalStateException("It's closed");
}
XSSFSheet spreadsheet = workbook.getSheetAt(0);
if (tipo .equals(CANDIDATOS_MINORISTA)) {
spreadsheet = workbook.getSheetAt(1);
}else if(tipo.equals(CONVERSION_CANDIDATOS)){
spreadsheet = workbook.getSheetAt(2);
}else if(tipo.equals(CUENTAS)){
spreadsheet = workbook.getSheetAt(3);
// etc, etc
}
return spreadsheet;
}
}
A couple of things to note :
If we want the caller to close the file, then we should explictly make them take some action to open it as well, otherwise it's too easy for it to be left hanging. In the example above, this is implicit in creating the object - just like the standard Java types like FileInputStream, etc.
Making RutaArchivo AutoCloseable means that it can used in try-with-resources, so closed automatically - eg :
try (RutaArchivo rutaArchivo = new RutaArchivo()) {
XSSFSheet cuentas = rutaArchivo.getSheet(RutaArchivo.CUENTAS);
}
Using constants for the names of the sheets reduces bugs (eg, no typos when the method is called)
As this is it's own class rather than static methods, it's easier to substitute or mock when writing unit tests.
Anyhow, a few thoughts - hope they help.
I'm using apache PDFBox from java, and I have a source PDF with multiple optional content groups. What I am wanting to do is export a version of the PDF that includes only the standard content and the optional content groups that were enabled. It is important for my purposes that I preserve any dynamic aspects of the original.... so text fields are still text fields, vector images are still vector images, etc. The reason that this is required is because I intend to ultimately be using a pdf form editor program that does not know how to handle optional content, and would blindly render all of them, so I want to preprocess the source pdf, and use the form editing program on a less cluttered destination pdf.
I've been trying to find something that could give me any hints on how to do this with google, but to no avail. I don't know if I'm just using the wrong search terms, or if this is just something that is outside of what the PDFBox API was designed for. I rather hope it's not the latter. The info shown here does not seem to work (converting the C# code to java), because despite the pdf I'm trying to import having optional content, there does not seem to be any OC resources when I examine the tokens on each page.
for(PDPage page:pages) {
PDResources resources = page.getResources();
PDFStreamParser parser = new PDFStreamParser(page);
parser.parse();
Collection tokens = parser.getTokens();
...
}
I'm truly sorry for not having any more code to show what I've tried so far, but I've just been poring over the java API docs for about 8 hours now trying to figure out what I might need to do this, and just haven't been able to figure it out.
What I DO know how to do is add text, lines, and images to a new PDPage, but I do not know how to retrieve that information from a given source page to copy it over, nor how to tell which optional content group such information is part of (if any). I am also not sure how to copy form fields in the source pdf over to the destination, nor how to copy the font information over.
Honestly, if there's a web page out there that I wasn't able to find with google with the searches that I tried, I'd be entirely happy to read up more about it, but I am really quite stuck here, and I don't know anyone personally that knows about this library.
Please help.
EDIT:
Trying what I understand from what was suggested below, I've written a loop to examine each XObject on the page as follows:
PDResources resources = pdPage.getResources();
Iterable<COSName> names = resources.getXObjectNames();
for(COSName name:names) {
PDXObject xobj = resources.getXObject(name);
PDFStreamParser parser = new PDFStreamParser(xobj.getStream().toByteArray());
parser.parse();
Object [] tokens = parser.getTokens().toArray();
for(int i = 0;i<tokens.length-1;i++) {
Object obj = tokens[i];
if (obj instanceof COSName && obj.equals(COSName.OC)) {
i++;
Object obj = tokens[i];
if (obj instanceof COSName) {
PDPropertyList props = resources.getProperties((COSName)obj);
if (props != null) {
...
However, after an OC key, the next entry in the tokens array is always an Operator tagged as "BMC". Nowhere am I finding any info that I can recognize from the named optional content groups.
Here's a robust solution for removing marked content blocks (open to feedback if anyone finds anything that isn't working right). You should be able to adjust for OC blocks...
This code properly handles nesting and removal of resources (xobject, graphics state and fonts - easy to add others if needed).
public class MarkedContentRemover {
private final MarkedContentMatcher matcher;
/**
*
*/
public MarkedContentRemover(MarkedContentMatcher matcher) {
this.matcher = matcher;
}
public int removeMarkedContent(PDDocument doc, PDPage page) throws IOException {
ResourceSuppressionTracker resourceSuppressionTracker = new ResourceSuppressionTracker();
PDResources pdResources = page.getResources();
PDFStreamParser pdParser = new PDFStreamParser(page);
PDStream newContents = new PDStream(doc);
OutputStream newContentOutput = newContents.createOutputStream(COSName.FLATE_DECODE);
ContentStreamWriter newContentWriter = new ContentStreamWriter(newContentOutput);
List<Object> operands = new ArrayList<>();
Operator operator = null;
Object token;
int suppressDepth = 0;
boolean resumeOutputOnNextOperator = false;
int removedCount = 0;
while (true) {
operands.clear();
token = pdParser.parseNextToken();
while(token != null && !(token instanceof Operator)) {
operands.add(token);
token = pdParser.parseNextToken();
}
operator = (Operator)token;
if (operator == null) break;
if (resumeOutputOnNextOperator) {
resumeOutputOnNextOperator = false;
suppressDepth--;
if (suppressDepth == 0)
removedCount++;
}
if (OperatorName.BEGIN_MARKED_CONTENT_SEQ.equals(operator.getName())
|| OperatorName.BEGIN_MARKED_CONTENT.equals(operator.getName())) {
COSName contentId = (COSName)operands.get(0);
final COSDictionary properties;
if (operands.size() > 1) {
Object propsOperand = operands.get(1);
if (propsOperand instanceof COSDictionary) {
properties = (COSDictionary) propsOperand;
} else if (propsOperand instanceof COSName) {
properties = pdResources.getProperties((COSName)propsOperand).getCOSObject();
} else {
properties = new COSDictionary();
}
} else {
properties = new COSDictionary();
}
if (matcher.matches(contentId, properties)) {
suppressDepth++;
}
}
if (OperatorName.END_MARKED_CONTENT.equals(operator.getName())) {
if (suppressDepth > 0)
resumeOutputOnNextOperator = true;
}
else if (OperatorName.SET_GRAPHICS_STATE_PARAMS.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.EXT_G_STATE, operands.get(0), suppressDepth == 0);
}
else if (OperatorName.DRAW_OBJECT.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.XOBJECT, operands.get(0), suppressDepth == 0);
}
else if (OperatorName.SET_FONT_AND_SIZE.equals(operator.getName())) {
resourceSuppressionTracker.markForOperator(COSName.FONT, operands.get(0), suppressDepth == 0);
}
if (suppressDepth == 0) {
newContentWriter.writeTokens(operands);
newContentWriter.writeTokens(operator);
}
}
if (resumeOutputOnNextOperator)
removedCount++;
newContentOutput.close();
page.setContents(newContents);
resourceSuppressionTracker.updateResources(pdResources);
return removedCount;
}
private static class ResourceSuppressionTracker{
// if the boolean is TRUE, then the resource should be removed. If the boolean is FALSE, the resource should not be removed
private final Map<COSName, Map<COSName, Boolean>> tracker = new HashMap<>();
public void markForOperator(COSName resourceType, Object resourceNameOperand, boolean preserve) {
if (!(resourceNameOperand instanceof COSName)) return;
if (preserve) {
markForPreservation(resourceType, (COSName)resourceNameOperand);
} else {
markForRemoval(resourceType, (COSName)resourceNameOperand);
}
}
public void markForRemoval(COSName resourceType, COSName refId) {
if (!resourceIsPreserved(resourceType, refId)) {
getResourceTracker(resourceType).put(refId, Boolean.TRUE);
}
}
public void markForPreservation(COSName resourceType, COSName refId) {
getResourceTracker(resourceType).put(refId, Boolean.FALSE);
}
public void updateResources(PDResources pdResources) {
for (Map.Entry<COSName, Map<COSName, Boolean>> resourceEntry : tracker.entrySet()) {
for(Map.Entry<COSName, Boolean> refEntry : resourceEntry.getValue().entrySet()) {
if (refEntry.getValue().equals(Boolean.TRUE)) {
pdResources.getCOSObject().getCOSDictionary(COSName.XOBJECT).removeItem(refEntry.getKey());
}
}
}
}
private boolean resourceIsPreserved(COSName resourceType, COSName refId) {
return getResourceTracker(resourceType).getOrDefault(refId, Boolean.FALSE);
}
private Map<COSName, Boolean> getResourceTracker(COSName resourceType){
if (!tracker.containsKey(resourceType)) {
tracker.put(resourceType, new HashMap<>());
}
return tracker.get(resourceType);
}
}
}
Helper class:
public interface MarkedContentMatcher {
public boolean matches(COSName contentId, COSDictionary props);
}
Optional Content Groups are marked with BDC and EMC. You will have to navigate through all of the tokens returned from the parser and remove the "section" from the array. Here is some C# Code that was posted a while ago - [1]: How to delete an optional content group alongwith its content from pdf using pdfbox?
I investigated that (converting to Java) but couldn't get it work as expected. I managed to remove the content between BDC and EMC and then save the result using the same technique as the sample but the PDF was corrupted. Perhaps that is my lack of C# Knowledge (related to Tuples etc.)
Here is what I came up with, as I said it doesn't work perhaps you or someone else (mkl, Tilman Hausherr) can spot the flaw.
OCGDelete (PDDocument doc, int pageNum, String OCName) {
PDPage pdPage = (PDPage) doc.getDocumentCatalog().getPages().get(pageNum);
PDResources pdResources = pdPage.getResources();
PDFStreamParser pdParser = new PDFStreamParser(pdPage);
int ocgStart
int ocgLength
Collection tokens = pdParser.getTokens();
Object[] newTokens = tokens.toArray()
try {
for (int index = 0; index < newTokens.length; index++) {
obj = newTokens[index]
if (obj instanceof COSName && obj.equals(COSName.OC)) {
// println "Found COSName at "+index /// Found Optional Content
startIndex = index
index++
if (index < newTokens.size()) {
obj = newTokens[index]
if (obj instanceof COSName) {
prop = pdRes.getProperties(obj)
if (prop != null && prop instanceof PDOptionalContentGroup) {
if ((prop.getName()).equals(delLayer)) {
println "Found the Layer to be deleted"
println "prop Name was " + prop.getName()
index++
if (index < newTokens.size()) {
obj = newTokens[index]
if ((obj.getName()).equals("BDC")) {
ocgStart = index
println("OCG Start " + ocgStart)
ocgLength = -1
index++
while (index < newTokens.size()) {
ocgLength++
obj = newTokens[index]
println " Loop through relevant OCG Tokens " + obj
if (obj instanceof Operator && (obj.getName()).equals("EMC")) {
println "the next obj was " + obj
println "after that " + newTokens[index + 1] + "and then " + newTokens[index + 2]
println("OCG End " + ocgLength++)
break
}
index++
}
if (endIndex > 0) {
println "End Index was something " + (startIndex + ocgLength)
}
}
}
}
}
}
}
}
}
}
catch (Exception ex){
println ex.message()
}
for (int i = ocgStart; i < ocgStart+ ocgLength; i++){
newTokens.removeAt(i)
}
PDStream newContents = new PDStream(doc);
OutputStream output = newContents.createOutputStream(COSName.FLATE_DECODE);
ContentStreamWriter writer = new ContentStreamWriter(output);
writer.writeTokens(newTokens);
output.close();
pdPage.setContents(newContents);
}
How do I rename a file using the Google Drive REST API on Android? I have searched the internet however I could, but I can't find how to do this.
I am trying to write a sync method that moves and renames the cloud files if it detects that the local copy has been moved or renamed:
void syncMetadataOnly (com.google.api.services.drive.model.File cloud,
java.io.File local) throws IOException {
Workspace.FINF fileInfo = Workspace.getFileInfo (this, local); // Just my metadata object.
Map<String, String> appProperties = cloud.getAppProperties ();
// We keep track of the last rename and move in our private app properties:
long cloudLastRename = appProperties.containsKey ("last-rename") ?
Long.valueOf (appProperties.get ("last-rename")) : 0;
long cloudLastMove = appProperties.containsKey ("last-move") ?
Long.valueOf (appProperties.get ("last-move")) : 0;
boolean needUpdate = false;
boolean needName = false;
boolean needMove = false;
if (fileInfo.lastRename > cloudLastRename) {
// The file was renamed locally since the last sync.
needName = true;
needUpdate = true;
} else fileInfo.title = cloud.getName ();
String oldRecognizedParent = null;
if (fileInfo.lastMove > cloudLastMove) {
// The file was moved to a different folder locally since the last sync.
oldRecognizedParent = getFirstKnownParentId (cloud); // May be null, if not found.
needMove = true;
needUpdate = true;
}
if (needUpdate) {
cloud.setAppProperties (appProperties);
Drive.Files.Update update = mDriveService.files ().update (fileInfo.driveResourceId, null);
if (needName) update.set /// How do I rename the file?
if (needMove) {
if (oldRecognizedParent != null)
update.setRemoveParents (oldRecognizedParent);
update.setAddParents (fileInfo.driveParentId); // Set to the NEW parent's ID.
}
com.google.api.services.drive.model.File result = update.execute ();
}
}
The closest answer I have found is this, but do I really have to use raw HTTP for this?
I have buildings' information stored in citygml file. I am trying to extract the building's polygon geometry using the citygml4j library. I have looked at the FeatureWalker class, but I am unable to get the polygon geometry.
How do I go about doing this? Here is my code:
CityGMLContext ctx = new CityGMLContext();
CityGMLBuilder builder = ctx.createCityGMLBuilder();
CityGMLInputFactory in = builder.createCityGMLInputFactory();
CityGMLReader reader = in.createCityGMLReader(new File("/home/vishal/NWW/sampleData/LOD2_Building_v100.gml"));
while(reader.hasNext())
{
CityGML citygml = reader.nextFeature();
System.out.println("Found class:" + citygml.getCityGMLClass() + "\nVersion"+citygml.getCityGMLModule().getVersion());
//Counting the no of buildings
CityModel citymodel = new CityModel();
if(citygml.getCityGMLClass() == CityGMLClass.CITY_MODEL)
{
citymodel = (CityModel)citygml;
// Counting the no of buildings
int count=0;
for(CityObjectMember cityObjectMember : citymodel.getCityObjectMember())
{
AbstractCityObject cityobject = cityObjectMember.getCityObject();
if(cityobject.getCityGMLClass() == CityGMLClass.BUILDING)
{
++count;
}
}
System.out.println("Building count"+count);
}
FeatureWalker walker = new FeatureWalker(){
public void visit(Building building){
System.out.println(building.getId());
//MultiSurface multisurface = boundrysurface.getLod2MultiSurface().getMultiSurface();
//System.out.println(multisurface.getSurfaceMember().get(0));
List<BoundarySurfaceProperty> list = building.getBoundedBySurface();
System.out.println(list);
System.out.println(list.get(0).getBoundarySurface());
//HOW TO GET THE POLYGON AND ITS COORDINATES??
}
};
citymodel.accept(walker);
PS: If you have any other resources/tutorials on citygml4j library, kindly let me know.
Thanks,
You can search for the AbstractBoundarySurfaces directly, like this:
FeatureWalker walker = new FeatureWalker() {
#Override
public void visit(AbstractBoundarySurface boundarySurface) {
MultiSurfaceProperty lod2MultiSurface = boundarySurface.getLod2MultiSurface();
if (lod2MultiSurface != null) {
MultiSurface multiSurface = lod2MultiSurface.getMultiSurface();
if (multiSurface == null) {
// Do something!
}
List<SurfaceProperty> surfaceMember = multiSurface.getSurfaceMember();
for (SurfaceProperty surfaceProperty : surfaceMember) {
AbstractSurface abstractSurface = surfaceProperty.getObject();
if (abstractSurface instanceof Polygon) {
Polygon polygon = (Polygon) abstractSurface;
// Do something with polygon!
}
// Check for other subtypes of AbstractSurface
}
}
// Process LOD3 and LOD4
super.visit(boundarySurface);
}
};
building.accept(walker);
Then you can traverse down the tree and look for the polygons.
I've got an Excel Spreadsheet in which I store all of the test Credit Cards. These credit cards have different types. Some of these are VISA, others are MasterCard, Amex etc...
I have got a test case in which I sometimes want to use VISA cards, and sometimes MasterCard cards.
Is it possible to pass parameters to the #DataProvider?
Here is my code for #DataProvider:
#DataProvider(name="dpCreditCards")
public Object[][] getCreditCards() {
Object[][] testData = null;
try {
FileInputStream fis = new FileInputStream(dir);
XSSFWorkbook workbook = new XSSFWorkbook(fis);
XSSFSheet worksheet = workbook.getSheet("Credit Cards");
String type = "";
String cardNumber = "";
int numOfRows = worksheet.getPhysicalNumberOfRows();
int j = 0;
if (numOfRows > 0) {
for (int i = 1; i < numOfRows; i++) {
XSSFRow r = worksheet.getRow(i);
if (r.getCell(0).getCellType() == Cell.CELL_TYPE_NUMERIC) {
type = Integer.toString((int)r.getCell(0).getNumericCellValue());
} else if (r.getCell(0).getCellType() == Cell.CELL_TYPE_STRING) {
type = r.getCell(0).getStringCellValue();
}
if (type.equalsIgnoreCase("visa"))
j++;
}
testData = new Object[j][1];
}
for (int i = 1; i < numOfRows; i++) {
XSSFRow r = worksheet.getRow(i);
if (r.getCell(0).getCellType() == Cell.CELL_TYPE_NUMERIC) {
type = Integer.toString((int)r.getCell(0).getNumericCellValue());
} else if (r.getCell(0).getCellType() == Cell.CELL_TYPE_STRING) {
type = r.getCell(0).getStringCellValue();
}
if (type.equalsIgnoreCase("visa")) {
if (r.getCell(1).getCellType() == Cell.CELL_TYPE_NUMERIC) {
cardNumber = Integer.toString((int)r.getCell(1).getNumericCellValue());
} else if (r.getCell(1).getCellType() == Cell.CELL_TYPE_STRING) {
cardNumber = r.getCell(1).getStringCellValue();
}
testData[i-1][0] = cardNumber;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return testData;
}
I've checked this link: http://testng.org/doc/documentation-main.html#parameters-dataproviders but couldn't find anything that would work for me. It suggests to pass Method m as parameter to data provider, but I couldn't find a useful method that m has.
Thanks in advance
One way could be to read the parameters in the listeners and then set a property which can be used in the dataprovider.
Implement ITestListener or ISuiteListener, depending upon how you are structuring your tests. Set the global card property or threadlocal property (again depending upon how you are running your tests sequentially/parallely) in the onStart methods of any.
Read this property in your dataprovider.
If you just want to test a subset of your data you could filter it out in your data provider.
If you want to apply different tests to different subsets of data, then you could use different data providers for each of the test methods. Or you could use tbe Method parameter to decide what data to return from your data provider.
If you want to be able to configure the type of data to be loaded for your test at runtime, you could use a env variable/system property for this.
Bottom line:
If you run the same test against different subsets of data, you have multiple ways to specify the subset you want to check
If you want to run different tests for different subsets of data then you should probably go with multiple data providers