Discussion:
Replacing placeholder to a Table.
André Peres
2011-02-19 16:11:09 UTC
Permalink
Hi.
I'm developing a project that need to generate reports in .doc format.
These reports are based on templeates where placeholders must be replace by
some content. My biggest problem is that some of this placeholder must be
replace by one or more tables.

There is a way to do this?

Sorry my bad english.

Thanks.
Mark Beardsley
2011-02-20 07:45:49 UTC
Permalink
This may sound a silly question but when you say you have to produce .doc
files, does that actually mean files in the older binary format with the
extension .doc or are you using the term generically to refer to any Word
file either in the binary or OOXML file formats? In the past, there have
been problems trying to use the api to undertake a search and replace
operation with HWPF. Your requirement sounds slightly different in that, I
am guessing, you will be replacing a simple tag with content rather than a
certain section of a paragraph, but it is best to acknowledge this potential
problem at the outset.

How complex are the tables? I am fairly certain, for instance, that it is
not yet possible to produce tables where a cell spans more than one row or
column. Further, I am not confident that it is possible to insert images
into table cells or to embed other documents but I could well be wrong as I
have not used this part of the api for quite some time and it could have
been developed further in the interim.

Yours

Mark B
--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3392925.html
Sent from the POI - User mailing list archive at Nabble.com.
André Peres
2011-02-20 11:44:49 UTC
Permalink
Hi Mark.

My personal preference was for the old format because of compatibility, but
if it is easier in the new format (OOXML) no problem.
Exact will change only a few tags for a word or two, the tables are quite
simple, text only with about 5 columns, the lines will vary according to
data from the database.


Thanks.
Post by Mark Beardsley
This may sound a silly question but when you say you have to produce .doc
files, does that actually mean files in the older binary format with the
extension .doc or are you using the term generically to refer to any Word
file either in the binary or OOXML file formats? In the past, there have
been problems trying to use the api to undertake a search and replace
operation with HWPF. Your requirement sounds slightly different in that, I
am guessing, you will be replacing a simple tag with content rather than a
certain section of a paragraph, but it is best to acknowledge this potential
problem at the outset.
How complex are the tables? I am fairly certain, for instance, that it is
not yet possible to produce tables where a cell spans more than one row or
column. Further, I am not confident that it is possible to insert images
into table cells or to embed other documents but I could well be wrong as I
have not used this part of the api for quite some time and it could have
been developed further in the interim.
Yours
Mark B
--
http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3392925.html
Sent from the POI - User mailing list archive at Nabble.com.
---------------------------------------------------------------------
Mark Beardsley
2011-02-21 07:49:30 UTC
Permalink
In my opinion, XWPF would be the better option for the simple reason that the
resulting files - the .docx OOXML files - are merely zipped xml which it is
easy to open and examine when and if problems occur. Also, it has been my
experience that HWPF can produce corrupt files if used for a search/replace
operation. Also the operation itself would not complete successfully if the
replacement term was longer than the serach term - the api threw an
exception if this occurred I believe. I have not tested the very latest
iteration of the api and things may well be better now of course.

At this point, and because I cannot offer any advice based upon concrete
experience with a recent iteration of the libraries, I can only reccommend
that you have a good search through the messages posted to the user list. I
remember someone using XWPF for a search and replace operation - I
contributed to the discussion early on but do not remember the conclusion -
but I am unsure about tables - again I know a question was asked about
merging rows/columns which we were unable to accomplish with the api at that
time. If I have the time this week, I will try to look out the test code I
have assembled to test the capabilities of both libraries and will post here
what I find. With luck, someone else far more experienced with these
specific libraries than I will see this thread and contribute to the
discussion. Also, it may well be the case that the libraries currently do
not have the capabaility to do exactly what you require. In that case, it
would be appreciated if you could work with the developers to add these
features.

Yours

Mark B
--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3393766.html
Sent from the POI - User mailing list archive at Nabble.com.
André Peres
2011-02-22 11:26:46 UTC
Permalink
I'm able to replace text searching the text in run and using string
operations to replace, works fine.
My problem is with tables, every time I try to create it appears in the end
of document, I've tried to use XWPFDocument.insertNewTbl with no success,
I'm able to edit a pre existing table but, as a said before, the project
demands that the tag must be replaced by one or MORE tables, and editing I
can just edit ONE table and can't add more.

So I need a way to create table at a specific point of document, defined by
a tag and be able to create more tables in sequence;

Thanks.
Post by Mark Beardsley
In my opinion, XWPF would be the better option for the simple reason that the
resulting files - the .docx OOXML files - are merely zipped xml which it is
easy to open and examine when and if problems occur. Also, it has been my
experience that HWPF can produce corrupt files if used for a search/replace
operation. Also the operation itself would not complete successfully if the
replacement term was longer than the serach term - the api threw an
exception if this occurred I believe. I have not tested the very latest
iteration of the api and things may well be better now of course.
At this point, and because I cannot offer any advice based upon concrete
experience with a recent iteration of the libraries, I can only reccommend
that you have a good search through the messages posted to the user list. I
remember someone using XWPF for a search and replace operation - I
contributed to the discussion early on but do not remember the conclusion -
but I am unsure about tables - again I know a question was asked about
merging rows/columns which we were unable to accomplish with the api at that
time. If I have the time this week, I will try to look out the test code I
have assembled to test the capabilities of both libraries and will post here
what I find. With luck, someone else far more experienced with these
specific libraries than I will see this thread and contribute to the
discussion. Also, it may well be the case that the libraries currently do
not have the capabaility to do exactly what you require. In that case, it
would be appreciated if you could work with the developers to add these
features.
Yours
Mark B
--
http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3393766.html
Sent from the POI - User mailing list archive at Nabble.com.
---------------------------------------------------------------------
Mark Beardsley
2011-02-22 17:15:07 UTC
Permalink
If I remember correctly, the correct way to do this is to use the
createTable() method of the XWPFDocument object. The only drwaback with this
is that I cannot see any way to position the table within the document. Have
you looked at using the insertTable(int XWPFTable) method yet. That promises
to allow you to position the table within the document although I am not
clear exactly how it works and you would need to experiement with various
different values for the first parameter just to see how that works. I am
guessing that you are able to position the table between paragraphs but I do
not know this for a fact, sorry. From the top of my head, I think you will
need to do something like this;

XWPFDocument document = new XWPFDocument(new FileInputStream(new
File(......)));

// Create the tbale object and then populate it
XWPFTable table = document.createTable(3, 4);

// Insert it nto the document
document.insertTable(2, table);

just what value you pass as the first parameter, I do not yet know but
suspect it to be the number of paragraphs that should precede the table in
the document but I cannot promise that this is the case at all.

Sadly, I will not have the time to play with any code for a day or so -
vandals, do not get me started on that problem, but I will try as soon as I
have some time. It may well be that what you want is beyond the capabilities
of the api as it currently stands but I do hope not. If that is the case,
you may want to consider working with the developers to create a patch that
supports the required functionality and then commit this to the project. The
final, fallback position, would be to unzip the document, work directly on
the raw xml and then zip it all up again. Not my preferred option by any
means but it might get you working quickly if time is pressing and the
project deadline is looming.

Yours

Mark B
--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3395841.html
Sent from the POI - User mailing list archive at Nabble.com.
Mark Beardsley
2011-02-26 12:21:57 UTC
Permalink
Hello again Andre,

I do not know if you are stil working on this problem but I have been a
little today and can report no p[rogress at all. It is a trivial task to
build a document sequentially; inserting a new paragraph followed by a table
followed by another paragraph, etc, but I cannot yet find a way to insert a
table between two existing paragraphs; whatever I try, the table simply
appears at the end of the document.

I think that the key lies in one of two places - allowing us to directly
update either the tables list or the body elements list, both of which are
protected and so inaccessible to client code. To date, I have not looked at
the source of the XWPF class but suspect that this is the way the
insertTable() and setTable() methods try to work. It would be perfect if we
could use the set/insertTable methods to allow us to position a table in the
document in it's correct location and I will look to see if this is
possible. As always, will be in touch if I make any progress.

Yours

Mark B
--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3401338.html
Sent from the POI - User mailing list archive at Nabble.com.
Brian Rosenberger
2011-06-26 15:57:42 UTC
Permalink
Hi,

I am facing the same problem. The insertTable() method correctly adds the table into the body element list (correct position between two paragraphs). But when the document is written, all tables end up at the end of the document.
However tables inserted by ms word remain at their original location.

Cheers
Brian

-----Ursprüngliche Nachricht-----
Von: Mark Beardsley [mailto:***@tiscali.co.uk]
Gesendet: Samstag, 26. Februar 2011 13:22
An: ***@poi.apache.org
Betreff: Re: Replacing placeholder to a Table.

Hello again Andre,

I do not know if you are stil working on this problem but I have been a little today and can report no p[rogress at all. It is a trivial task to build a document sequentially; inserting a new paragraph followed by a table followed by another paragraph, etc, but I cannot yet find a way to insert a table between two existing paragraphs; whatever I try, the table simply appears at the end of the document.

I think that the key lies in one of two places - allowing us to directly update either the tables list or the body elements list, both of which are protected and so inaccessible to client code. To date, I have not looked at the source of the XWPF class but suspect that this is the way the
insertTable() and setTable() methods try to work. It would be perfect if we could use the set/insertTable methods to allow us to position a table in the document in it's correct location and I will look to see if this is possible. As always, will be in touch if I make any progress.

Yours

Mark B

--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3401338.html
Sent from the POI - User mailing list archive at Nabble.com.
Brian Rosenberger
2011-06-27 09:56:20 UTC
Permalink
Hi,

I have drilled down the problem to how xmlbeans exposes a <xsd:sequence> of <xsd:choice> where the available choices do not have a common basetype.

Here is an extract of CTBody schema from wml.xsd:
<xsd:choice>
<xsd:element name="customXml" type="CT_CustomXmlBlock">
<xsd:annotation>
<xsd:documentation>Block-Level Custom XML Element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="sdt" type="CT_SdtBlock">
<xsd:annotation>
<xsd:documentation>Block-Level Structured Document Tag</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="p" type="CT_P" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>Paragraph</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>Table</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:group ref="EG_RunLevelElts" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>

Each element is exposed through a separate list, thus ordering is lost. I have found how to preserve ordering when doing read access (http://article.gmane.org/gmane.text.xml.xmlbeans.user/2639/match=choice+sequence+order), but I don't have an idea how to write elements in a specific order as there is no shared list of them. My only current idea is to dump the xml of the bodyElements (CTP and CTTbl) into a string (with correct ordering) and the CTBody.Factory.parse them into a CTBody again. Very ugly.

Any better approaches?

Cheers
Brian

-----Ursprüngliche Nachricht-----
Von: Brian Rosenberger [mailto:***@serena.com]
Gesendet: Sonntag, 26. Juni 2011 17:58
An: ***@poi.apache.org
Betreff: AW: Replacing placeholder to a Table.

Hi,

I am facing the same problem. The insertTable() method correctly adds the table into the body element list (correct position between two paragraphs). But when the document is written, all tables end up at the end of the document.
However tables inserted by ms word remain at their original location.

Cheers
Brian

-----Ursprüngliche Nachricht-----
Von: Mark Beardsley [mailto:***@tiscali.co.uk]
Gesendet: Samstag, 26. Februar 2011 13:22
An: ***@poi.apache.org
Betreff: Re: Replacing placeholder to a Table.

Hello again Andre,

I do not know if you are stil working on this problem but I have been a little today and can report no p[rogress at all. It is a trivial task to build a document sequentially; inserting a new paragraph followed by a table followed by another paragraph, etc, but I cannot yet find a way to insert a table between two existing paragraphs; whatever I try, the table simply appears at the end of the document.

I think that the key lies in one of two places - allowing us to directly update either the tables list or the body elements list, both of which are protected and so inaccessible to client code. To date, I have not looked at the source of the XWPF class but suspect that this is the way the
insertTable() and setTable() methods try to work. It would be perfect if we could use the set/insertTable methods to allow us to position a table in the document in it's correct location and I will look to see if this is possible. As always, will be in touch if I make any progress.

Yours

Mark B

--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p3401338.html
Sent from the POI - User mailing list archive at Nabble.com.



---------------------------------------------------------------------
To unsubscribe, e-mail: user-***@poi.apache.org For additional commands, e-mail: user-***@poi.apache.org
Nick Burch
2011-06-27 10:38:26 UTC
Permalink
Post by Brian Rosenberger
Each element is exposed through a separate list, thus ordering is lost.
I think we should be maintaining a list with both paragraphs and tables in
it though, with relative ordering preserved. On XWPFDocument there's
List<IBodyElement> bodyElements
for example, which is built by doing a child walk and storing the entries
in the order they occur

I'd look at extending that to suit your needs

Nick
Brian Rosenberger
2011-07-27 17:03:42 UTC
Permalink
Hi Nick,

meanwhile I've created a small test class that indicates the problem. I have a table between two paragraphs and I simply would like to re-sort those IBodyElements, so that the table is first - followed by two paragraphs.
When I simply try to resort the list or to replace it, I get an UnmodifiableCollection Exception.

Against TAG REL_3_8_BETA3:

package net.brutex.msd2docx;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.xwpf.usermodel.*;

public class Test {
static String outputfile = "c:/temp/testdoc.docx";

public static void main(String[] args) {
try {
//Create an XWPFDoc and put a table between two
//paragraphs
XWPFDocument d = new XWPFDocument();
XWPFParagraph p1 = d.createParagraph();
XWPFRun r1= p1.createRun();
r1.setText("Paragraph 1, Run 1.");
XWPFTable t1 = d.createTable(4, 3);
t1.getRow(0).getCell(0).setText("Table 1");
XWPFParagraph p2 = d.createParagraph();
XWPFRun r2= p2.createRun();
r2.setText("Paragraph 2, Run 2.");

//Howto move table t1 to another position,
//i.e. above p1 ?

//Just list the IBodyElement List
List<IBodyElement> list = d.getBodyElements();
int i=0;
for ( IBodyElement e : list ) {
System.out.println(i + ": " + e.getElementType().name());
i++;
}

d.write(new FileOutputStream(outputfile));

} catch (Exception e) {
e.printStackTrace();
}
}
}

Cheers
Brian





Von: Nick Burch [mailto:***@alfresco.com]
Gesendet: Montag, 27. Juni 2011 12:38

I think we should be maintaining a list with both paragraphs and tables in it though, with relative ordering preserved. On XWPFDocument there's
List<IBodyElement> bodyElements
for example, which is built by doing a child walk and storing the entries in the order they occur

I'd look at extending that to suit your needs

Nick
primeq
2012-03-28 11:36:23 UTC
Permalink
Nick,

I'm unable to find any more information on what seems to still be inability
to place a new table in a specified location (i.e. not at the bottom of the
document).

Do you know if there have been any changes, or any new advice on how to make
the table go where I want (happens I also want to put it within a
table-cell)
Post by Nick Burch
Post by Brian Rosenberger
Each element is exposed through a separate list, thus ordering is lost.
I think we should be maintaining a list with both paragraphs and tables in
it though, with relative ordering preserved. On XWPFDocument there's
List<IBodyElement> bodyElements
for example, which is built by doing a child walk and storing the entries
in the order they occur
I'd look at extending that to suit your needs
Nick
---------------------------------------------------------------------
--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p5600175.html
Sent from the POI - User mailing list archive at Nabble.com.
IsadorCJ
2012-05-30 05:43:24 UTC
Permalink
I have a way of dealing with the "replacement" issue. I have tried serveral
days, but cannot finish the task. (a similar task as the OP had).
So my approach is create an empty List<IBodyElement>
so now you read in your templates, according to the templates, construct
paragraphs and tables, and then stuff them into the list with order.
and then you can use a for loop:
XWPFDocument newDoc = new XWPFDocument();
for(IBodyElement element : list){
if(element.getElementType().equals("PARAGRAPH"){
XWPFParagraph pr = newDoc.createParagraph();
newDoc.setParagraph((XWPFParagraph) element, newDoc.getPosOfParagrah(pr));
}
}
and add your if condition to table.......by doing the same.....

this will do the trick~ i've proven it work.

but this has a serious problem: if there is a picture in the original
document, it will show as a "broken linked picture" like what you see on
website, and tells you the picture currently cannot be showed.


--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p5709992.html
Sent from the POI - User mailing list archive at Nabble.com.
sars84
2013-02-06 16:45:55 UTC
Permalink
Hi;

I have now the same Problem. i tried this way, but no success.
Did you got another solution for the table or what had you done?
----
XWPFDocument newDoc = new XWPFDocument();
for(IBodyElement element : list){
if(element.getElementType().equals("TABLE"){
XWPFTable tb = newDoc.createTable();
newDoc.setTable(newDoc.getPosOfTable(tb), tableToAdd);
}
}
---

I need some support, please...
Thanks in advance.
sars



--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p5712072.html
Sent from the POI - User mailing list archive at Nabble.com.
Mark Beardsley
2013-02-10 08:43:07 UTC
Permalink
Sorry to say this but you will need to download the source for the project
and create a patch for XWPF yourself so that it handles the insertion of
tables correctly. Remember that POI is not a commercial product and that
everyone that works on it does so as a volunteer. Typically, people develop
areas of the api as they need that specific functionality; it seems as
though you have a pressing need to work with tables and so are the ideal
person to enhance this part.

The problem may not be as simple as it seems. Yesterday, I played around
with some test code and found that the createTable() methods do create a new
table that is added to the bottom of the list of body elements. If a call to
the setTable() method is made, this will move the position of the table in
the body element list but seems to create a second entry; it appears to
leave the original entry at the bottom of the list and then create a second
entry in the correct position. Confusingly however, saving this document
creates xml markup with just a single copy of the table, the one created at
the bottom of the list of body elements and it seems to me that the write
process it doing something a little strange. To confirm this, I created the
new table directly myself and then set it into the document. This did result
in a list of body elements that showed a single entry for the table and in
the correct position. It still, however, resulted in the markup being
created with the table at the end of the document. This is why I suspect
that something is awry with the writing of the markup when the document is
saved, no proof just a suspicion.

I cannot investigate further myself - not clever enough to dig around in the
source code of the api - but this is what I feel you will have to do. Find
out how the list of body elements is processed when the document is saved
and why the position of the table within it is being ignored when a new
table - seemingly, existing tables read in from documents are handled
properly but I have yet to fully confirm this - is created and I think you
will have the answer.



--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p5712081.html
Sent from the POI - User mailing list archive at Nabble.com.
Jaakov Jalink
2013-08-27 14:55:07 UTC
Permalink
Encountered this issue a few hours ago, here is my solution:

XmlCursor cursor = doc.getDocument().getBody().newCursor();
cursor.selectPath("./*");
while (cursor.toNextSelection()) {
XmlObject o = cursor.getObject();
if (o instanceof CTP) {
XWPFParagraph paragraph = new XWPFParagraph((CTP) o, doc);
for (CTR run : paragraph.getCTP().getRList()) {
for (CTText text : run.getTList()) {
if(newText.indexOf("POSITION")>-1){
newText = newText.replaceAll("POSITION", "");//remove place holder
text
text.setStringValue(newText);

XWPFTable tableOne = paragraph.getBody().insertNewTbl(c);
}
}
}
} else if (o instanceof CTTbl) {
XWPFTable t = new XWPFTable((CTTbl) o, doc);//i don't care about these
right now
}
}
cursor.dispose();

Where POSITION is place holder in for where the table should be
Table is placed right before the paragraph with the placeholder

The trick with insertNewTbl is that the cursor has to come from the document
body, otherwise it returns null (see XWPFDocument source)

Note - ooxml-schemas-1.1.jar required for this to work ( download link
<http://repo1.maven.org/maven2/org/apache/poi/ooxml-schemas/1.1/> )



--
View this message in context: http://apache-poi.1045710.n5.nabble.com/Replacing-placeholder-to-a-Table-tp3392424p5713654.html
Sent from the POI - User mailing list archive at Nabble.com.

Continue reading on narkive:
Loading...