I am generating a PDF file using Itext.
I have to add an unordered list (bullet list).
I am using the following code which works fine.
List unorderedList = new List(List.UNORDERED);
unorderedList.setListSymbol("\u2022");
String lista = desc.split(":");
for (String li : lis) {
if (item.length() > 0) {
unorderedList.add(new ListItem(" " + item, ARIALFONT_SIZE_11));
}
}
PdfPCell items = new PdfPCell(new Phrase("", ARIALFONT_SIZE_11));
items.addElement(unorderedList);
table.addCell(items);
The code works fine.
The question is how I can set the space between lines in the list.
Thanks in advance!
ListItems are Paragraphs - try playing with their spacingBefore and spacingAfter settings.
Related
I'm using OpenPDF to generate a document.
In this document i want to have certain elements grouped so that they don't get split on a seperate page.
In my case that consists of a paragraph surrounded by 2 lines, 1 above and 1 below.
I've tried grouping them inside a Paragraph element and using the keepTogether property, but then the lines don't show up:
for (final String line : lines) {
Paragraph para = new Paragraph(line, font);
para.setSpacingAfter(20);
doc.add(para);
para.add(new LineSeparator());
para.add(0, new LineSeparator());
para.setKeepTogether(true);
}
Is there any way i can keep these together at all times? or are there better suggestions?
info
language: Java
java version: openjdk 8
OpenPDF version: 1.3.17
I used a table as a workaround like this:
PdfPTable table = new PdfPTable(1);
table.setTotalWidth(527);
table.setLockedWidth(true);
for (final String line : lines) {
PdfPCell cell = new PdfPCell(new Phrase(line, font));
cell.setBorder(Rectangle.BOTTOM | Rectangle.TOP);
cell.setPaddingBottom(20);
cell.setPaddingTop(20);
table.addCell(cell);
}
doc.add(table);
I have a word document which is used as a template. Inside this template I have some tables that contain predefined bullet points. Now I'm trying to replace the placeholder string with a set of strings.
I'm totally stuck on this. My simplified methods looks like this.
replaceKeyValue.put("[DescriptionOfItem]", new HashSet<>(Collections.singletonList("This is the description")));
replaceKeyValue.put("[AllowedEntities]", new HashSet<>(Arrays.asList("a", "b")));
replaceKeyValue.put("[OptionalEntities]", new HashSet<>(Arrays.asList("c", "d")));
replaceKeyValue.put("[NotAllowedEntities]", new HashSet<>(Arrays.asList("e", "f")));
try (XWPFDocument template = new XWPFDocument(OPCPackage.open(file))) {
template.getTables().forEach(
xwpfTable -> xwpfTable.getRows().forEach(
xwpfTableRow -> xwpfTableRow.getTableCells().forEach(
xwpfTableCell -> replaceInCell(replaceKeyValue, xwpfTableCell)
)
));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
template.write(baos);
return new ByteArrayResource(baos.toByteArray());
} finally {
if (file.exists()) {
file.delete();
}
}
private void replaceInCell(Map<String, Set<String>> replacementsKeyValuePairs, XWPFTableCell xwpfTableCell) {
for (XWPFParagraph xwpfParagraph : xwpfTableCell.getParagraphs()) {
for (Map.Entry<String, Set<String>> replPair : replacementsKeyValuePairs.entrySet()) {
String keyToFind = replPair.getKey();
Set<String> replacementStrings = replacementsKeyValuePairs.get(keyToFind);
if (xwpfParagraph.getText().contains(keyToFind)) {
replacementStrings.forEach(replacementString -> {
XWPFParagraph paragraph = xwpfTableCell.addParagraph();
XWPFRun run = paragraph.createRun();
run.setText(replacementString);
});
}
}
}
I was expecting that some more bullet points will be added to the current cell. Am I missing something? The paragraph is the one containing the placeholder string and format.
Thanks for any help!
UPDATE: This is how part of the template looks like. I would like to automatically search for the terms and replace them. Searching works so far. But trying to replace the bullet points ends in an unlocatable NullPointer.
Would it be easier to use fields? I need to keep the bullet point style though.
UPDATE 2: added download link and updated the code. Seems I can't alter the paragraphs if I'm iterating through them. I get a null-pointer.
Download link: WordTemplate
Since Microsoft Word is very, very "strange" in how it divides text in different runs in it's storage, such questions are not possible to answer without having a complete example including all code and the Word documents in question. Having a general usable code for adding content to Word documents seems not be possible, except all the adding or replacement is only in fields (form fields or content controls or mail merge fields).
So I downloaded your WordTemplate.docx which looks like so:
Then I runned the following code:
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
import org.apache.xmlbeans.XmlCursor;
import java.util.*;
import java.math.BigInteger;
public class WordReadAndRewrite {
static void addItems(XWPFTableCell cell, XWPFParagraph paragraph, Set<String> items) {
XmlCursor cursor = null;
XWPFRun run = null;
CTR cTR = null; // for a deep copy of the run's low level object
BigInteger numID = paragraph.getNumID();
int indentationLeft = paragraph.getIndentationLeft();
int indentationHanging = paragraph.getIndentationHanging();
boolean first = true;
for (String item : items) {
if (first) {
for (int r = paragraph.getRuns().size()-1; r > 0; r--) {
paragraph.removeRun(r);
}
run = (paragraph.getRuns().size() > 0)?paragraph.getRuns().get(0):null;
if (run == null) run = paragraph.createRun();
run.setText(item, 0);
cTR = (CTR)run.getCTR().copy(); // take a deep copy of the run's low level object
first = false;
} else {
cursor = paragraph.getCTP().newCursor();
boolean thereWasParagraphAfter = cursor.toNextSibling(); // move cursor to next paragraph
// because the new paragraph shall be **after** that paragraph
// thereWasParagraphAfter is true if there is a next paragraph, else false
if (thereWasParagraphAfter) {
paragraph = cell.insertNewParagraph(cursor); // insert new paragraph if there are next paragraphs in cell
} else {
paragraph = cell.addParagraph(); // add new paragraph if there are no other paragraphs present in cell
}
paragraph.setNumID(numID); // set template paragraph's numbering Id
paragraph.setIndentationLeft(indentationLeft); // set template paragraph's indenting from left
if (indentationHanging != -1) paragraph.setIndentationHanging(indentationHanging); // set template paragraph's hanging indenting
run = paragraph.createRun();
if (cTR != null) run.getCTR().set(cTR); // set template paragraph's run formatting
run.setText(item, 0);
}
}
}
public static void main(String[] args) throws Exception {
Map<String, Set<String>> replaceKeyValue = new HashMap<String, Set<String>>();
replaceKeyValue.put("[AllowedEntities]", new HashSet<>(Arrays.asList("allowed 1", "allowed 2", "allowed 3")));
replaceKeyValue.put("[OptionalEntities]", new HashSet<>(Arrays.asList("optional 1", "optional 2", "optional 3")));
replaceKeyValue.put("[NotAllowedEntities]", new HashSet<>(Arrays.asList("not allowed 1", "not allowed 2", "not allowed 3")));
XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
List<XWPFTable> tables = document.getTables();
for (XWPFTable table : tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row : rows) {
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
int countParagraphs = cell.getParagraphs().size();
for (int p = 0; p < countParagraphs; p++) { // do not for each since new paragraphs were added
XWPFParagraph paragraph = cell.getParagraphArray(p);
String placeholder = paragraph.getText();
placeholder = placeholder.trim(); // this is the tricky part to get really the correct placeholder
Set<String> items = replaceKeyValue.get(placeholder);
if (items != null) {
addItems(cell, paragraph, items);
}
}
}
}
}
FileOutputStream out = new FileOutputStream("Result.docx");
document.write(out);
out.close();
document.close();
}
}
The Result.docx looks like so:
The code loops trough the table cells in the Word document and looks for a paragraph which contains exactly the placeholder. This even might be the tricky part since that placeholder might be splitted into differnt text runs by Word. If found it runs a method addItems which takes the found paragraph as a template for numbering and indention (might be incomplter though). Then it sets the first new item in first text run of found paragraph and removes all other text runs which possibly are there. Then it determines wheter new paragraphs must be inserted or added to the cell. For this a XmlCursor is used. In new inserted or added paragrahs the other items are placed and the numbering and indention settings are taken from the placeholder's paragraph.
As said, this is code for showing the principles of how to do. It would must be extended very much to be general usable. In my opinion those trials using text placeholders in Word documents for text replacements are not really good. Placeholders for variable text in Word documents should be fields. This could be form fields, content controls or mail merge fields. Advantage of fields in contrast of text placeholders is that Word knows the fields being entities for variable texts. It will not split them into multiple text runs for multiple strange reasons as it often does with normal text.
I am doing a selenium test against a web page which returns a table with some rows and columns showing payment data. I'm trying to strip some characters/words from the result of the XPATH i'm using because i dont need the part while doing an assertion (check if the data in table is correct).
Normally the webpage also returns a "Dropdown Button" as text (there is an icon), just before the identification number (e.g 168.3285.6021 as seen below).
What i used is it.set(it.next().replaceAll("DropDown Arrow ","")); so the DropDown Arrow text is replaced with nothing, which only works for the first line, but the other 2 lines don't get replaced. Any tips?
public void check_receivals() {
// Check how many lines and assert the size (from xpath)
List<WebElement> Receivals = driver.findElements(By.xpath("//*[#id='received-overview']//div[#class='bdpo-overview-table-row']/div[#class='claims']"));
System.out.println(Receivals.size() + " receival lines found");
assertEquals(7, Receivals.size());
// Test data to compare against..aka expectedResultList
List<String> expectedResultList = new ArrayList<>();
expectedResultList.add ("168.3285.6021\n" + "Payment 2015\n" + "01-01-2015\n" + "€ 246");
expectedResultList.add ("143.8407.8413\n" + "Payment 2015\n" + "01-01-2015\n" + "€ 233");
expectedResultList.add ("154.2841.2407\n" + "Payment 2015\n" + "01-01-2015\n" + "€ 253");
// Assert
List<WebElement> ReceivalLines = driver.findElements(By.xpath("//*[#id='received-overview']//div[#class='bdpo-overview-table-row']/div[#class='claims']"));
List<String> ReceivalLines_List = ReceivalLines.stream().map(WebElement::getText).collect(Collectors.toList());
ListIterator<String> it = ReceivalLines_List.listIterator();
while(it.hasNext()) {
it.set(it.next().replaceAll("DropDown Arrow ",""));
assertEquals(ReceivalLines_List, expectedResultList);
THe issue is that you are modifying the iterator as you are working with it. I would suggest making the replace part of the stream operation using the map function.
List<String> ReceivalLines_List = ReceivalLines.stream().map(WebElement::getText).map(s -> s.replaceAll("DropDown Arrow ","")).collect(Collectors.toList());
I'm trying to display a list of strings (filenames, to be pedant) inside a GtkTreeView. I'm creating a single column and trying to fill it with a CellRenderText.
//Setup listview
TreeView imageList = (TreeView)gladeBuilder.getObject("imageListTreeView");
TreeViewColumn column = imageList.appendColumn();
DataColumnString imageColumnString = new DataColumnString();
//Fill listview
ListStore listStore = new ListStore(new DataColumnString[]{imageColumnString});
File[] imageFiles = new File("/path/to/files").listFiles();
// For each file:
for (File file : imageFiles) {
TreeIter row = listStore.appendRow(); //add a row
listStore.setValue(row, imageColumnString, file.getName());
}
CellRendererText cellRendererText = new CellRendererText(column);
cellRendererText.setText(imageColumnString);
The program compiles and run without errors, but the list is displayed empty. Someone can help me to find the error(s)?
Add imageList.set_model (listStore) which actually associates your view with the model. This is required or the view will stay empty as it has no model associate unless you specified it in the builder file which I can only guess at this point.
Hello everybody I want to get the data from
http://sansoyunlari.hurriyet.com.tr/SayisalLoto/SayisalLotoSonuclari.aspx this adress by using jsoup ı can get them but only the latest results . There is a dropdownlist on the website which consists dates how can I reach other dates ? by the way I will move these codes to the android these are codes which is written in netbeans for now. ı will put a dropdownlist to my android program which get the data from this adress and also the results.
these are my java codes I wrote until now
public static void main(String[] args) {
String adres = "http://sansoyunlari.hurriyet.com.tr/SayisalLoto/SayisalLotoSonuclari.aspx";
ArrayList sayi = new ArrayList<>();
sayi.add("six");
sayi.add("five");
sayi.add("four");
sayi.add("three");
sayi.add("two");
sayi.add("one");
//Sayısal Loto
try {
Document doc = Jsoup.connect(adres).get();
Elements sonuclar = doc.select("div.hurriyet2010_so_sanstopu_no_bg");
//1. yi manuel almak gerek ilk yoldan çünkü resut diye kodlanmış
Elements sonuclar1 = doc.select("span#_ctl0_ContentPlaceHolder1_lblresut"+sayi.get(sayi.size()-1));
Element numaralar = sonuclar1.first();
System.out.println(numaralar.text());
//yol 1 numaraları almak için
for (int i = sonuclar.size();i>1;i--)
{
sonuclar1 = doc.select("span#_ctl0_ContentPlaceHolder1_lblresult"+sayi.get(i-2));
Element numaralar1 = sonuclar1.first();
System.out.println(numaralar1.text());
}
//yol 2 numaraları almak için
// for(Element el : sonuclar)
// {
// System.out.println(el.text());
// }
//kazanan kişi sayısı ve ikramiye tutarı için
for(int i = 0;i<4;i++)
{
int b = 6 -i;
System.out.println(b + " bilen kişi sayısı :");
sonuclar = doc.select("span#_ctl0_ContentPlaceHolder1_lblluckycount"+sayi.get(i));
Element el = sonuclar.first();
System.out.println(el.text());
System.out.println("Kişi başına düşen ikramiye :");
sonuclar = doc.select("span#_ctl0_ContentPlaceHolder1_lblluckyamount"+sayi.get(i));
el = sonuclar.first();
System.out.println(el.text());
}
}
catch(Exception e){
}
}
To get the select item you should do:
Element select = doc.select("#_ctl0_ContentPlaceHolder1_ddlSayisalLotoDates").first();
Now the children of this elements are the "option" items you want:
for (Element e : select) {
String date = e.text();
}
edit
I looked at the html source. In order to get the right page you need to do a post request at the URL "http://sansoyunlari.hurriyet.com.tr/SayisalLoto/SayisalLotoSonuclari.aspx" with following params:
__EVENTARGUMENT = empty
__EVENTTARGET = _ctl0$ContentPlaceHolder1$ddlSayisalLotoDates
__EVENTVALIDATION = a random value that you get from the html page
__LASTFOCUS = empty
__VIEWSTATE = another random value
_ctl0:ContentPlaceHolder1:ddlSayisalLotoDates = The ID of the date you want to search (i.e. 884 for 19 Ekim 2013)
txtSearch = can be empty
As you can see, it's quite annoying scraping an ASP.NET webpage..
Use an application like Fiddler (or another one) to find the params you need to post (hidden inputs, session cookies, your selected input). Probably you're missing some of them.
Hope it helps.