Some time ago, I received a requirement for a Web application to automatically generate a Word. Now I have sorted out some key steps to share them.
Ideas:(Note: This is only applicable to the WORD2003 version. Other versions are similar .)
Because the data and format inside the WORD file are stored in the form of XML files, it is very convenient for WORD files to convert from DOC to XML formats, XML files are much more convenient to operate. In this way, various platform-independent operations are implemented, and Word files are generated through node query, replacement, deletion, and addition. Therefore, the process of generating a WORD file based on the template is to replace the special tags in the XML file with user data and then save it as a DOC file.
The following are some of the key steps involved (take the letter of introduction as an example)
Step 1: Create a WORD template as needed
Create a WORD file in DOC format, enter the template content as needed, and set the template format, including fonts, styles, and empty rows. use special labels for the data to be filled (for example: [※organization name ※]) pre-placeholder, and then save the New WORD file as an XML file. In this way, the WORD template is created, and the code is as follows:
Step 2: configure the template information in the configuration file
Add a configuration file named template-rule.xml, each template node corresponds to a template type. Each template has a taglist node. All the child nodes in the node contain all information about the nodes to be replaced and deleted in the template. The Node information includes the node value, node attribute name in English, and Chinese description, field type, whether to delete, and other information. When setting this configuration file,Note:The value of the desc attribute must be consistent with the placeholder in the template XML. For example, the year set in the template XML entry [※※year※] needs to correspond to the desc = "year' name in the template-rule.xml, the Code is as follows:
<? Xml version = "1.0" encoding = "GB2312"?> <! -- Template definition --> <templates> <! -- Note: S-string, D-date, E-amount, M-capital amount, and ifEmptyDelete: The T-value is null to delete the parent node, the default value is F --> <template name = "RECOMMEND-LETTER" desc = "" templateFile = "template4.xml"> <taglist remark = "Single-value tag list"> <tag id = "1" name = "ToPartment" desc = "receiving department" type = "S" ifEmptyDelete = "T" ># ToPartment </tag> <! -- Receiving department --> <tag id = "2" name = "OwnerName" desc = "name" type = "S"> # OwnerName </tag> <! -- Name --> <tag id = "3" name = "CountNum" desc = "count" type = "S"> # CountNum </tag> <! -- Number of people --> <tag id = "4" name = "Business" desc = "content" type = "S" >#business </tag> <! -- Content --> <tag id = "5" name = "UsefulDays" desc = "validity period" type = "S"> # UsefulDays </tag> <! -- Validity Period --> <tag id = "6" name = "Year" desc = "Year" type = "S"> # Year </tag> <! -- Year --> <tag id = "7" name = "Month" desc = "Month" type = "S"> # Month </tag> <! -- Month --> <tag id = "8" name = "Day" desc = "Day" type = "S"> # Day </tag> <! -- Day --> </taglist> </template> </templates>
Step 3: Write java code
/*** Parameters and Rules */public class RuleDTO {/*** tag name */private String parmName;/*** tag Description */private String parmDesc; /*** tag serial number */private String parmSeq;/*** tag value type */private String parmType;/*** tag parameter name */private String parmRegular; /*** tag value */private String parmValue;/*** the tag value is null to delete this attribute */private String ifEmptyDelete ;}
/*** Description: Word Template information */public class Template {private String name; // Template name private String desc; // Template description private String templateFile; // template file private Vector <RuleDTO> rules; // template rule}
Public class WordBuilder {/*** read replacement rules based on the Template * @ param templateName Template ID */@ SuppressWarnings ("unchecked") public Template loadRules (Map <String, String> ruleValue) {InputStream in = null; Template template = new Template (); // rule configuration file path String ruleFile = "template-rule.xml"; // Template rule name String templateRuleName = ""; try {templateRuleName = ruleValue. get ("ruleName"); // read the template rule file in = this. getClass (). getClassLoader (). GetResourceAsStream (ruleFile); // parse the template rule SAXBuilder sb = new SAXBuilder (); Document doc = sb. build (in); Element root = doc. getRootElement (); // obtain the root Element List <Element> templateList = root. getChildren (); // All templates configure Element element = null; Vector <RuleDTO> rules = null; for (int I = 0; I <templateList. size (); I ++) {// traverse all template elements = (element) templateList. get (I); String templateName = element. getAttributeValue ("Name"); if (templateRuleName. equalsIgnoreCase (templateName) {// find the template configured for the given template. setName (templateName); template. setDesc (element. getAttributeValue ("desc"); template. setTemplateFile (element. getAttributeValue ("templateFile"); List <Element> tagList = (Element) element. getChildren (). get (0 )). getChildren (); // tag list Element tag = null; RuleDTO ruleDTO = null; rules = new Vector <RuleDTO> (); for (int j = 0; J <tagList. size (); j ++) {tag = (Element) tagList. get (j); ruleDTO = new RuleDTO (); ruleDTO. setParmName (tag. getAttributeValue ("name"); ruleDTO. setParmDesc ("[※" + tag. getAttributeValue ("desc") + "※]"); ruleDTO. setParmSeq (tag. getAttributeValue ("id"); ruleDTO. setParmType (tag. getAttributeValue ("type"); if ("T ". equalsIgnoreCase (tag. getAttributeValue ("ifEmptyDelete") {// whether the tag ruleDTO can be deleted. setIfEmptyDelete ("T" );} Else {ruleDTO. setIfEmptyDelete ("F");} ruleDTO. setParmRegular (tag. getText (); // value // judge the parameter type String value = (String) (Map <String, String>) ruleValue ). get (ruleDTO. getParmRegular (). replaceAll ("#", ""); ruleDTO. setParmValue (value); rules. add (ruleDTO);} template. setRules (rules); break ;}} catch (FileNotFoundException e) {e. printStackTrace ();} catch (JDOMException e) {e. printStackTrace ();} catch (IOExcepti On e) {e. printStackTrace ();} finally {try {in. close ();} catch (Exception e) {e. printStackTrace () ;}} return template;}/*** find parent node */public Element findElement (Element currNode, String parentNodeId) {// if (currNode = null | parentNodeId = null) {return null;} Element pNode = null; do {pNode = currNode. getParent (); currNode = pNode;} while (parentNodeId. equalsIgnoreCase (pNode. getName (); return PNode;}/*** generate the Word file */@ SuppressWarnings ("unchecked") public String build (Template template) {InputStream in = null; OutputStream fo = null; // generate the file path String file = "d: \ test \" + template. getDesc () + ". doc "; try {// read the template file in = this. getClass (). getClassLoader (). getResourceAsStream (template. getTemplateFile (); SAXBuilder sb = new SAXBuilder (); Document doc = sb. build (in); Element root = doc. getRootElemen T (); // obtain the root element Namespace ns = root. getNamespace (); // NameSpace // word 03 template <wx: sect> Element List <Element> sectList = root. getChild ("body", ns ). getChildren (); Element sectElement = (Element) sectList. get (0); // List of tag sets under <w: p> <Element> pTagList = sectElement. getChildren ("p", ns); // List of tag sets under <w: tbl> <Element> tblTagList = sectElement. getChildren ("tbl", ns); if (pTagList! = Null & pTagList. size ()> 0) {changeValue4PTag (pTagList, template. getRules (), ns, null);} if (tblTagList! = Null & tblTagList. size ()> 0) {changeValue4TblTag (tblTagList, template. getRules (), ns);} // write the file XMLOutputter outp = new XMLOutputter ("", true, "UTF-8"); fo = new FileOutputStream (file); outp. output (doc, fo);} catch (FileNotFoundException e) {e. printStackTrace ();} catch (JDOMException e) {e. printStackTrace ();} catch (IOException e) {e. printStackTrace ();} finally {try {in. close (); fo. close ();} catch (Exception e) {e. printStackTrace () ;}} return file ;}/ *** for the <w: body> <wx: sect> <w: p> level WORD template, search for and replace tags under <w: p>. * @ Param pTagList: <w: p> Set * @ param rulesValue: RuleDTO Set * @ param ns: NameSpace object * @ param trChildren: <w: tbl> subnode <w: tr> Set */@ SuppressWarnings ("unchecked") private boolean changeValue4PTag (List <Element> pTagList, Vector <RuleDTO> rulesValue, Namespace ns, list <Element> trChildren) {Element p = null; boolean delFlag = false; for (int I = 0; I <pTagList. size (); I ++) {boolean delCurrNode = false; // Delete the current Node boolean delCurrNode4TabWR = false; // Delete the single row node p = (Element) pTagList in the table. get (I); List <Element> pChild = p. getChildren ("r", ns); for (int j = 0; pChild! = Null & j <pChild. size (); j ++) {Element pChildren = (Element) pChild. get (j); Element t = pChildren. getChild ("t", ns); if (t! = Null) {String text = t. getTextTrim (); if (text. indexOf ("【※")! =-1) {for (int v = 0; v <rulesValue. size (); v ++) {RuleDTO dto = (RuleDTO) rulesValue. get (v); if (text. indexOf (dto. getParmDesc (). trim ())! =-1) {// determines whether the property value is empty to delete if ("T ". equals (dto. getIfEmptyDelete () & StringUtils. isBlank (dto. getParmValue () {// Delete the top-level node text = ""; if (trChildren! = Null) {// Delete the Row Element = (element) p for <w: tbl>. getParent ()). getParent (); trChildren. remove (element); delCurrNode4TabWR = true;} else {// For <w: r> deleting segments // pTagList. remove (p); pTagList. remove (pChildren); delCurrNode = true;} break;} else {text = text. replaceAll (dto. getParmDesc (). trim (), dto. getParmValue () ;}}} t. setText (text);} if (delCurrNode4TabWR) {// <w: tbl> the row node in the TABLE has been deleted. delFlag = true; break;} else If (delCurrNode) {// The node under <w: p> has been deleted I --; delFlag = true; break ;}}} return delFlag ;} /*** search for and replace the labels under <w: tbl> for WORD Templates containing tables. * @ Param tblTagList: <w: tbl> Set * @ param rulesValue: RuleDTO Set * @ param ns: NameSpace object */@ SuppressWarnings ("unchecked ") private void changeValue4TblTag (List <Element> tblTagList, Vector <RuleDTO> rulesValue, Namespace ns) {Element p = null; for (int I = 0; tblTagList! = Null & I <tblTagList. size (); I ++) {p = (Element) tblTagList. get (I); List <Element> trChildren = p. getChildren ("tr", ns); for (int j = 0; trChildren! = Null & j <trChildren. size (); j ++) {// loop <w: tr> Element pChildren = (Element) trChildren. get (j); List <Element> tcTagList = pChildren. getChildren ("tc", ns); for (int c = 0; tcTagList! = Null & c <tcTagList. size (); c ++) {// loop <w: tc> obtains the <w: p> set Element tcChildren = (Element) tcTagList. get (c); List <Element> pTagList = tcChildren. getChildren ("p", ns); boolean delFlag = changeValue4PTag (pTagList, rulesValue, ns, trChildren); if (delFlag) {// After deleting the row, you need to change the pointer position of trChildren j -- ;}}} public static void main (String [] args) throws Exception {WordBuilder word = new WordBuilder (); Map <String, String> map = new HashMap <String, String> (); // fill in the map parameter. put ("ToPartment", "XXX company"); map. put ("OwnerName", "Zhang San"); map. put ("CountNum", "5"); map. put ("Business", "routine check"); map. put ("UsefulDays", "15"); map. put ("years", "2014"); map. put ("Month", "5"); map. put ("Day", "13"); map. put ("ruleName", "RECOMMEND-LETTER"); Template template = word. loadRules (map); // directly open the file runtime.getruntime(cmd.exe c ("explorer" + word. build (template ));}}
Step 4: Success
Summary and precautions:
1. The defined element name must be consistent with the value of the same name in template_rule.xml; otherwise, a conversion rule must be set.
2. The text in the placeholder [※※※] defined in template xml must be the same as the desc in template_rule.xml; otherwise, the conversion rule must be set.
3. after the template XML is configured, check whether the subnode under the <w: body> label is a <wx: sect> label (related to the WORD version). If no, this label must be added.
4. If you want to dynamically Delete the <w: p> label node, the content of this node must be in the same row in the template. If not, you can manually adjust the template XML.
5. if you need to implement the WORD auto-wrapping function (the new line wrapping scheme in the template is not expected to be better), you need to calculate the number of words in the corresponding template line, and then use space filling.