You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@pdfbox.apache.org by Tolen Miller <to...@msn.com> on 2015/10/12 00:46:40 UTC

Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

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:

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);
}
}

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?

Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi Torben,

> Am 24.10.2015 um 18:21 schrieb Tolen Miller <to...@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 <sa...@fileaffairs.de>
> wrote:
> 
>> Hi,
>> 
>>> Am 23.10.2015 um 06:16 schrieb Tolen Miller <to...@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 <sa...@fileaffairs.de>
>>> wrote:
>>> 
>>>> Hi,
>>>> 
>>>>> Am 12.10.2015 um 00:46 schrieb Tolen Miller <to...@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


Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

Posted by Tolen Miller <to...@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>?


On Thu, Oct 22, 2015 at 10:29 PM Maruan Sahyoun <sa...@fileaffairs.de>
wrote:

> Hi,
>
> > Am 23.10.2015 um 06:16 schrieb Tolen Miller <to...@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 <sa...@fileaffairs.de>
> > wrote:
> >
> >> Hi,
> >>
> >>> Am 12.10.2015 um 00:46 schrieb Tolen Miller <to...@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
>
>

Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi,

> Am 23.10.2015 um 06:16 schrieb Tolen Miller <to...@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 <sa...@fileaffairs.de>
> wrote:
> 
>> Hi,
>> 
>>> Am 12.10.2015 um 00:46 schrieb Tolen Miller <to...@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


Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

Posted by Tolen Miller <to...@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?

Link to test version of PDF <http://1drv.ms/1hREdXQ>

On Sun, Oct 11, 2015 at 11:54 PM Maruan Sahyoun <sa...@fileaffairs.de>
wrote:

> Hi,
>
> > Am 12.10.2015 um 00:46 schrieb Tolen Miller <to...@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?
>
>

Re: Hybrid XFA (Livecycle) PDF - setting values of text fields in XFA

Posted by Maruan Sahyoun <sa...@fileaffairs.de>.
Hi,

> Am 12.10.2015 um 00:46 schrieb Tolen Miller <to...@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?