pdfbox-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Maruan Sahyoun <sahy...@fileaffairs.de>
Subject Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA
Date Sun, 25 Oct 2015 05:54:43 GMT
Hi Torben,

> Am 24.10.2015 um 18:21 schrieb Tolen Miller <tolenmiller@gmail.com>:
> 
> I've tried setting the XFA a few ways. First, I tried simply setting the
> XFA with the original, but I assume that this does not work because I'm
> working on the Document (xml) that is a copy and no longer associated with
> the xfa:
> ...
> * PDXFA xfa = acroForm.getXFA();*
> * Document xmlDoc = xfa.getDocument();*
> * Node xfaData = xmlDoc.getElementsByTagName("xfa:data").item(0);*
> *        setDataElements(xfaData, notesFields);  // edit xml doc*
> *        acroForm.setXFA(xfa);*
> ...
> Second, I tried creating a new xfa object by grabbing the original xfa
> COSObject, though that seems the same as the first attempt.
> ...
> *        PDXFA newXfa = new PDXFA(xfa.getCOSObject());*
> *        acroForm.setXFA(newXfa);*
> ...
> Now I'm wondering if I am supposed to work my way back up the object model,
> after I set the XFA? something like:
> *docCatalog.setAcroForm(acroForm);*
> 
> Or am I supposed to create a new XFA, then put my XML in a stream and get
> it into the new XFA object somehow? (as described here for an older version
> <http://stackoverflow.com/questions/24149361>) Or stop using the Document
> class and go straight to the COS model with something like is suggested here
> <http://stackoverflow.com/questions/10536334>?


yes, the two stackoverflow article show the correct way of doing it.

Basically what you have to do it
- get the XFA (as you already do)
- do the manipulation (as you already do)
- create a new COSStream or PDStream serializing your XML into it ( which you don't seem to
be doing)
- create a new PDXFA from that ( which you don't seem to be doing)
- set the new PDXFA to be used by the AcroForm.

BR
Maruan
 

> 
> 
> On Thu, Oct 22, 2015 at 10:29 PM Maruan Sahyoun <sahyoun@fileaffairs.de>
> wrote:
> 
>> Hi,
>> 
>>> Am 23.10.2015 um 06:16 schrieb Tolen Miller <tolenmiller@msn.com>:
>>> 
>>> Thank you for the response. Indeed I was unaware that xfa:data was just a
>>> marker showing the start of the nodes that may contain data...
>>> 
>>> After implementing the recursion Maruan suggeted, I am no longer seeing
>> my
>>> PDFs filled despite my sysout showing the code locating and updating the
>>> values.
>>> 
>>> In my implementation, I pass in a hashmap with field names and values
>> from
>>> my database. Then, if I find a node with a matching name, I set the value
>>> of the xfa node:
>>> 
>>> *    public static void setDataElements(Node node, HashMap<String,
>> String>
>>> dbData) {*
>>> *        NodeList nodeList = node.getChildNodes();*
>>> *        for (int i = 0; i < nodeList.getLength(); i++) {*
>>> *            Node currentNode = nodeList.item(i);*
>>> *            if (currentNode.getNodeType() == Node.ELEMENT_NODE &&
>>> currentNode.hasChildNodes()) {*
>>> *                //calls this method for all the children which is
>> Element*
>>> *                setDataElements(currentNode, dbData);*
>>> *            } else {*
>>> *            currentNode.setNodeValue( dbData.get(
>>> currentNode.getNodeName() ) );*
>>> *            System.out.println("Matching XML Field found: " + *
>>> *            currentNode.getNodeName() + *
>>> *            " Setting Value to: " + *
>>> *            dbData.get( currentNode.getNodeName() ));*
>>> *//                dbData.put(currentNode.getNodeName(),
>>> currentNode.getNodeValue());*
>>> *            }*
>>> *        }*
>>> *    }*
>>> 
>>> Do I then need to set the PDXFA with setXfa()? or should I just be able
>> to
>>> save the pdf after modifying the Document ( retrieved via
>>> PDXFA.getDocument() ) and have the values show up?
>> 
>> you need to setXfa() as the changes you've done are to the XML Document
>> but not yet back in the PDF
>> 
>> BR
>> Maruan
>> 
>>> 
>>> Link to test version of PDF <http://1drv.ms/1hREdXQ>
>>> 
>>> On Sun, Oct 11, 2015 at 11:54 PM Maruan Sahyoun <sahyoun@fileaffairs.de>
>>> wrote:
>>> 
>>>> Hi,
>>>> 
>>>>> Am 12.10.2015 um 00:46 schrieb Tolen Miller <tolenmiller@msn.com>:
>>>>> 
>>>>> I'm using version 1.8.10 and had some great help in a previous thread
>>>>> (subject: Cannot load pre existing PDF to access fields). I have been
>>>> able
>>>>> to successfully load a pre existing fill-able PDF (created in
>> LiveCycle);
>>>>> get a map of text fields from the getFieldNameList() method; then use
a
>>>>> comparison of the field name on the pdf and name of the database field
>> to
>>>>> map values onto the pdf.
>>>>> 
>>>>> In the end of that thread, I mentioned my own trouble with also filling
>>>> the
>>>>> XFA portion of the form. In the end, I opted to rip out the XFA
>>>> (acroForm.
>>>>> setXFA(null);) in order to get the filled static PDF to display in
>>>> Adobe's
>>>>> products. I have been working on another project in the past few weeks,
>>>> but
>>>>> am again looking at filling the XFA. After looking at the PDXFA, I am
>>>>> having trouble getting a similar map or list of text field names from
>> the
>>>>> XFA. This was my first attempt, but I'm not getting what I was
>> expecting:
>>>> 
>>>> 
>>>> would it be possible to upload a sample form to a public location to
>> take
>>>> a closer look?
>>>> 
>>>>> 
>>>>> System.out.println("Setting up XFA");
>>>>> PDXFA xfa = acroForm.getXFA();
>>>>> Document xmlDoc = xfa.getDocument();
>>>>> NodeList dataElements = xmlDoc.getElementsByTagName("xfa:data");
>>>>> HashMap<String, Integer> xmlFields = new HashMap<String, Integer>();
>>>>> if (dataElements != null) {
>>>>> for (int i = 0; i < dataElements.getLength(); i++) {
>>>>> xmlFields.put(dataElements.item(0).getNodeName(), i);
>>>>> }
>>>>> }
>>>>> 
>>>> 
>>>> your need to recurse down into the nodes below xfa:data. Something like
>>>> 
>>>> 
>>>> 
>>>>   public static void main(String[] args) throws IOException,
>>>> ParserConfigurationException, SAXException
>>>>   {
>>>>       PDDocument document = PDDocument.loadNonSeq(...);
>>>>       PDXFA xfa = document.getDocumentCatalog().getAcroForm().getXFA();
>>>>       Document xmlDoc = xfa.getDocument();
>>>>       Node xfaData = xmlDoc.getElementsByTagName("xfa:data").item(0);
>>>>       HashMap<String, String> xmlFields = new HashMap<String,
>> String>();
>>>> 
>>>>       getDataElements(xfaData, xmlFields);
>>>> 
>>>>       System.out.println(xmlFields);
>>>> 
>>>>   }
>>>> 
>>>>   public static void getDataElements(Node node, HashMap<String, String>
>>>> xmlFields) {
>>>>       NodeList nodeList = node.getChildNodes();
>>>>       for (int i = 0; i < nodeList.getLength(); i++) {
>>>>           Node currentNode = nodeList.item(i);
>>>>           if (currentNode.getNodeType() == Node.ELEMENT_NODE &&
>>>> currentNode.hasChildNodes()) {
>>>>               //calls this method for all the children which is Element
>>>>               getDataElements(currentNode, xmlFields);
>>>>           } else {
>>>>               xmlFields.put(currentNode.getNodeName(),
>>>> currentNode.getNodeValue());
>>>>           }
>>>>       }
>>>>   }
>>>> 
>>>> 
>>>> It could also be that xfa:data is empty or doesn't have all fields e.g.
>>>> for dynamic forms. To get the fields as designed you need to look into
>> the
>>>> template node and look for subform and field nodes. Things can get a
>> little
>>>> more complicated as there is a <traversal> and there might be a <bind>
>>>> elements which tell you a little more about the structure of the form
>> and
>>>> the data binding of an element. <bind> is there if the data binding
for
>> the
>>>> field is not done by matching the field name. A small snippet below
>>>> 
>>>> 
>>>>           <field h="6.35mm" name="txtOrderedByCompanyName" w="82.55mm"
>>>> y="52.07mm">
>>>>              <ui>
>>>>                 <textEdit>
>>>>                    <border>
>>>>                       <edge presence="hidden"/>
>>>>                       <edge presence="hidden"/>
>>>>                       <edge/>
>>>>                       <edge presence="hidden"/>
>>>>                    </border>
>>>>                    <margin/>
>>>>                 </textEdit>
>>>>              </ui>
>>>>              <font size="9pt" typeface="Myriad Pro"/>
>>>>              <margin bottomInset="0mm" leftInset="0mm" rightInset="0mm"
>>>> topInset="0mm"/>
>>>>              <para marginLeft="0pt" vAlign="middle"/>
>>>>              <caption reserve="15.24mm">
>>>>                 <para vAlign="middle"/>
>>>>                 <value>
>>>>                    <text>Company</text>
>>>>                 </value>
>>>>              </caption>
>>>>              <traversal>
>>>>                 <traverse ref="header[0].txtOrderedByAddress[0]"/>
>>>>              </traversal>
>>>>              <bind match="dataRef" ref="$.CompanyName"/>
>>>>           </field>
>>>> 
>>>> 
>>>> BR
>>>> Maruan
>>>> 
>>>> 
>>>> 
>>>> 
>>>>> My hope, after that code snippet, was to match on the String of the
>>>>> xmlFields map with a field name from my db, then use the int as the
>>>>> position of the dataElements list to set the text value (which would
>> show
>>>>> as the filled value in the pdf).  Where have I gone wrong?
>>>> 
>>>> 
>> 
>> 
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
>> For additional commands, e-mail: users-help@pdfbox.apache.org
>> 
>> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@pdfbox.apache.org
For additional commands, e-mail: users-help@pdfbox.apache.org


Mime
View raw message