📄 xfaform.java
字号:
/*
* $Id: XfaForm.java 2768 2007-05-21 08:48:44Z blowagie $
*
* Copyright 2006 Paulo Soares
*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*
* The Original Code is 'iText, a free JAVA-PDF library'.
*
* The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
* the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
* All Rights Reserved.
* Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
* are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
*
* Contributor(s): all the names of the contributors are added in the source code
* where applicable.
*
* Alternatively, the contents of this file may be used under the terms of the
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
* provisions of LGPL are applicable instead of those above. If you wish to
* allow use of your version of this file only under the terms of the LGPL
* License and not to allow others to use your version of this file under
* the MPL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the LGPL.
* If you do not delete the provisions above, a recipient may use your version
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MPL as stated above or under the terms of the GNU
* Library General Public License as published by the Free Software Foundation;
* either version 2 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
* details.
*
* If you didn't download this code from the following link, you should check if
* you aren't using an obsolete version:
* http://www.lowagie.com/iText/
*/
package com.lowagie.text.pdf;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import com.lowagie.text.xml.XmlDomWriter;
/**
* Processes XFA forms.
* @author Paulo Soares (psoares@consiste.pt)
*/
public class XfaForm {
private Xml2SomTemplate templateSom;
private Xml2SomDatasets datasetsSom;
private AcroFieldsSearch acroFieldsSom;
private PdfReader reader;
private boolean xfaPresent;
private org.w3c.dom.Document domDocument;
private boolean changed;
private Node datasetsNode;
public static final String XFA_DATA_SCHEMA = "http://www.xfa.org/schema/xfa-data/1.0/";
/**
* An empty constructor to build on.
*/
public XfaForm() {
}
/**
* A constructor from a <CODE>PdfReader</CODE>. It basically does everything
* from finding the XFA stream to the XML parsing.
* @param reader the reader
* @throws java.io.IOException on error
* @throws javax.xml.parsers.ParserConfigurationException on error
* @throws org.xml.sax.SAXException on error
*/
public XfaForm(PdfReader reader) throws IOException, ParserConfigurationException, SAXException {
this.reader = reader;
PdfDictionary af = (PdfDictionary)PdfReader.getPdfObjectRelease(reader.getCatalog().get(PdfName.ACROFORM));
if (af == null) {
xfaPresent = false;
return;
}
PdfObject xfa = PdfReader.getPdfObjectRelease(af.get(PdfName.XFA));
if (xfa == null) {
xfaPresent = false;
return;
}
xfaPresent = true;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
if (xfa.isArray()) {
ArrayList ar = ((PdfArray)xfa).getArrayList();
for (int k = 1; k < ar.size(); k += 2) {
PdfObject ob = PdfReader.getPdfObject((PdfObject)ar.get(k));
if (ob instanceof PRStream) {
byte[] b = PdfReader.getStreamBytes((PRStream)ob);
bout.write(b);
}
}
}
else if (xfa instanceof PRStream) {
byte[] b = PdfReader.getStreamBytes((PRStream)xfa);
bout.write(b);
}
bout.close();
DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
fact.setNamespaceAware(true);
DocumentBuilder db = fact.newDocumentBuilder();
domDocument = db.parse(new ByteArrayInputStream(bout.toByteArray()));
Node n = domDocument.getFirstChild();
n = n.getFirstChild();
while (n != null) {
if (n.getNodeType() == Node.ELEMENT_NODE) {
String s = n.getLocalName();
if (s.equals("template")) {
templateSom = new Xml2SomTemplate(n);
}
else if (s.equals("datasets")) {
datasetsNode = n;
datasetsSom = new Xml2SomDatasets(n.getFirstChild());
}
}
n = n.getNextSibling();
}
}
/**
* Sets the XFA key from a byte array. The old XFA is erased.
* @param xfaData the data
* @param reader the reader
* @param writer the writer
* @throws java.io.IOException on error
*/
public static void setXfa(byte[] xfaData, PdfReader reader, PdfWriter writer) throws IOException {
PdfDictionary af = (PdfDictionary)PdfReader.getPdfObjectRelease(reader.getCatalog().get(PdfName.ACROFORM));
if (af == null) {
return;
}
reader.killXref(af.get(PdfName.XFA));
PdfStream str = new PdfStream(xfaData);
str.flateCompress();
PdfIndirectReference ref = writer.addToBody(str).getIndirectReference();
af.put(PdfName.XFA, ref);
}
/**
* Sets the XFA key from the instance data. The old XFA is erased.
* @param writer the writer
* @throws java.io.IOException on error
*/
public void setXfa(PdfWriter writer) throws IOException {
setXfa(serializeDoc(domDocument), reader, writer);
}
/**
* Serializes a XML document to a byte array.
* @param n the XML document
* @throws java.io.IOException on error
* @return the serialized XML document
*/
public static byte[] serializeDoc(Node n) throws IOException {
XmlDomWriter xw = new XmlDomWriter();
ByteArrayOutputStream fout = new ByteArrayOutputStream();
xw.setOutput(fout, null);
xw.setCanonical(false);
xw.write(n);
fout.close();
return fout.toByteArray();
}
/**
* Returns <CODE>true</CODE> if it is a XFA form.
* @return <CODE>true</CODE> if it is a XFA form
*/
public boolean isXfaPresent() {
return xfaPresent;
}
/**
* Gets the top level DOM document.
* @return the top level DOM document
*/
public org.w3c.dom.Document getDomDocument() {
return domDocument;
}
/**
* Finds the complete field name contained in the "classic" forms from a partial
* name.
* @param name the complete or partial name
* @param af the fields
* @return the complete name or <CODE>null</CODE> if not found
*/
public String findFieldName(String name, AcroFields af) {
HashMap items = af.getFields();
if (items.containsKey(name))
return name;
if (acroFieldsSom == null) {
acroFieldsSom = new AcroFieldsSearch(items.keySet());
}
if (acroFieldsSom.getAcroShort2LongName().containsKey(name))
return (String)acroFieldsSom.getAcroShort2LongName().get(name);
return acroFieldsSom.inverseSearchGlobal(Xml2Som.splitParts(name));
}
/**
* Finds the complete SOM name contained in the datasets section from a
* possibly partial name.
* @param name the complete or partial name
* @return the complete name or <CODE>null</CODE> if not found
*/
public String findDatasetsName(String name) {
if (datasetsSom.getName2Node().containsKey(name))
return name;
return datasetsSom.inverseSearchGlobal(Xml2Som.splitParts(name));
}
/**
* Finds the <CODE>Node</CODE> contained in the datasets section from a
* possibly partial name.
* @param name the complete or partial name
* @return the <CODE>Node</CODE> or <CODE>null</CODE> if not found
*/
public Node findDatasetsNode(String name) {
if (name == null)
return null;
name = findDatasetsName(name);
if (name == null)
return null;
return (Node)datasetsSom.getName2Node().get(name);
}
/**
* Gets all the text contained in the child nodes of this node.
* @param n the <CODE>Node</CODE>
* @return the text found or "" if no text was found
*/
public static String getNodeText(Node n) {
if (n == null)
return "";
return getNodeText(n, "");
}
private static String getNodeText(Node n, String name) {
Node n2 = n.getFirstChild();
while (n2 != null) {
if (n2.getNodeType() == Node.ELEMENT_NODE) {
name = getNodeText(n2, name);
}
else if (n2.getNodeType() == Node.TEXT_NODE) {
name += n2.getNodeValue();
}
n2 = n2.getNextSibling();
}
return name;
}
/**
* Sets the text of this node. All the child's node are deleted and a new
* child text node is created.
* @param n the <CODE>Node</CODE> to add the text to
* @param text the text to add
*/
public void setNodeText(Node n, String text) {
if (n == null)
return;
Node nc = null;
while ((nc = n.getFirstChild()) != null) {
n.removeChild(nc);
}
if (n.getAttributes().getNamedItemNS(XFA_DATA_SCHEMA, "dataNode") != null)
n.getAttributes().removeNamedItemNS(XFA_DATA_SCHEMA, "dataNode");
n.appendChild(domDocument.createTextNode(text));
changed = true;
}
/**
* Sets the XFA form flag signaling that this is a valid XFA form.
* @param xfaPresent the XFA form flag signaling that this is a valid XFA form
*/
public void setXfaPresent(boolean xfaPresent) {
this.xfaPresent = xfaPresent;
}
/**
* Sets the top DOM document.
* @param domDocument the top DOM document
*/
public void setDomDocument(org.w3c.dom.Document domDocument) {
this.domDocument = domDocument;
}
/**
* Gets the <CODE>PdfReader</CODE> used by this instance.
* @return the <CODE>PdfReader</CODE> used by this instance
*/
public PdfReader getReader() {
return reader;
}
/**
* Sets the <CODE>PdfReader</CODE> to be used by this instance.
* @param reader the <CODE>PdfReader</CODE> to be used by this instance
*/
public void setReader(PdfReader reader) {
this.reader = reader;
}
/**
* Checks if this XFA form was changed.
* @return <CODE>true</CODE> if this XFA form was changed
*/
public boolean isChanged() {
return changed;
}
/**
* Sets the changed status of this XFA instance.
* @param changed the changed status of this XFA instance
*/
public void setChanged(boolean changed) {
this.changed = changed;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -