zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Web应用Word生成

应用Web 生成 word
2023-09-14 09:02:07 时间

    前段时间接到一个Web应用自动生成Word的需求,现整理了下一些关键步骤拿来分享一下。

 

思路:(注:这里只针对WORD2003版本,其它版本大同小异。)

因为WORD文件内部的数据及格式等是通过XML文件的形式存储的,所以WORD文件可以很方便的实现由DOC到XML格式的相互转换,而操作XML文件就方便的多了,这样就实现了与平台无关的各种操作,通过节点的查询、替换、删除、新增等生成Word文件。所以,根据模板生成WORD文件实质就是由用户数据替换XML文件中特殊标签,然后另存为一个DOC文件的过程。

 

下面列举涉及到的一些关键步骤(以介绍信为例)

第一步:根据需求制作WORD模板

新建一个DOC格式的WORD文件,根据需要填写好模板内容,设置好模板的格式,包括字体,样式,空行等等,需要填充的数据使用特殊标签(如:【※单位名称※】)预先占位,然后将新建的WORD文件另存为XML格式文件。这样, WORD模板就制作完成了,代码如下:

 template4.xml
 

第二步:在配置文件中配置好模板信息

新增名为template-rule.xml的配置文件,每个template节点对应一个模板类型。每个template中有一个taglist节点,该节点包含的所有子节点包含了模板所有将要替换、删除节点信息,节点信息包括:节点值,节点属性英文名称,中文描述,字段类型,可否删除等信息。在设置这个配置文件时候,需要注意desc属性的值必须与模板XML中的占位符一致。比如:模板XML中设置的年份这个录入项【※年※】需与template-rule.xml中的desc="年"名称对应,代码如下:

  


templates         !-- 说明: S-字符串; D-日期; E-金额; M-大写金额; ifEmptyDelete: T-值为空删除父节点,默认为F --         template name="RECOMMEND-LETTER" desc="介绍信" templateFile="template4.xml"             taglist remark="单值标签列表"                 tag id="1" name="ToPartment" desc="接收部门" type="S" ifEmptyDelete="T" #ToPartment /tag !--接收部门--                 tag id="2" name="OwnerName" desc="姓名" type="S" #OwnerName /tag !--姓名--                 tag id="3" name="CountNum" desc="人数" type="S" #CountNum /tag !--人数--                 tag id="4" name="Business" desc="内容" type="S" #Business /tag !--内容--                 tag id="5" name="UsefulDays" desc="有效期" type="S" #UsefulDays /tag !--有效期--                 tag id="6" name="Year" desc="年" type="S" #Year /tag !--年--                 tag id="7" name="Month" desc="月" type="S" #Month /tag !--月--                 tag id="8" name="Day" desc="日" type="S" #Day /tag !--日--             /taglist         /template    /templates   
    @SuppressWarnings("unchecked")       public Template loadRules(Map String, String  ruleValue) {           InputStream in = null;           Template template = new Template();           // 规则配置文件路径           String ruleFile = "template-rule.xml";           // 模板规则名称           String templateRuleName = "";           try {               templateRuleName = ruleValue.get("ruleName");               // 读取模板规则文件               in = this.getClass().getClassLoader().getResourceAsStream(ruleFile);               // 解析模板规则               SAXBuilder sb = new SAXBuilder();               Document doc = sb.build(in);               Element root = doc.getRootElement(); // 得到根元素               List Element  templateList = root.getChildren();// 所有模板配置               Element element = null;               Vector RuleDTO  rules = null;               for (int i = 0; i   templateList.size(); i++) {// 遍历所有模板                   element = (Element) templateList.get(i);                   String templateName = element.getAttributeValue("name");                   if (templateRuleName.equalsIgnoreCase(templateName)) {// 查找给定的模板配置                       template.setName(templateName);                       template.setDesc(element.getAttributeValue("desc"));                       template.setTemplateFile(element                               .getAttributeValue("templateFile"));                       List Element  tagList = ((Element) element.getChildren()                               .get(0)).getChildren();// tag列表                       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"))) {// 是否可删除标记                               ruleDTO.setIfEmptyDelete("T");                           } else {                               ruleDTO.setIfEmptyDelete("F");                           }                           ruleDTO.setParmRegular(tag.getText());                           // 值                           // 判断参数类型                           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 (IOException e) {               e.printStackTrace();           } finally {               try {                   in.close();               } catch (Exception e) {                   e.printStackTrace();               }           }           return template;       }       /**       * 查找父节点       */       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;       }       /**       * 生成Word文件       */       @SuppressWarnings("unchecked")       public String build(Template template) {           InputStream in = null;           OutputStream fo = null;           // 生成文件的路径           String file = "d:\\test\\" + template.getDesc() + ".doc";           try {               // 读取模板文件               in = this.getClass().getClassLoader()                       .getResourceAsStream(template.getTemplateFile());               SAXBuilder sb = new SAXBuilder();               Document doc = sb.build(in);               Element root = doc.getRootElement(); // 得到根元素               Namespace ns = root.getNamespace();// NameSpace               // word 03模板存在 wx:sect 元素               List Element  sectList = root.getChild("body", ns).getChildren();               Element sectElement = (Element) sectList.get(0);               //  w:p 下的标签集合               List Element  pTagList = sectElement.getChildren("p", ns);               //  w:tbl 下的标签集合               List 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);               }               // 写文件               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;       }       /**       * 针对 w:body wx:sect w:p 这种层级的WORD模板, 查找及替换 w:p 下的标签。       * @param pTagList : w:p 集合       * @param rulesValue :RuleDTO集合       * @param ns :NameSpace对象       * @param trChildren : w:tbl 的子节点 w:tr 集合       */       @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;// 删除当前节点               boolean delCurrNode4TabWR = false;// 删除table中单行节点               p = (Element) pTagList.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) {                                   // 判断属性值是否为可空删除                                   if ("T".equals(dto.getIfEmptyDelete())                                             StringUtils.isBlank(dto                                                   .getParmValue())) {                                       // 删除该节点顶级节点                                       text = "";                                       if (trChildren != null) {// 针对 w:tbl 删除该行                                           Element element = ((Element) p                                                   .getParent()).getParent();                                           trChildren.remove(element);                                           delCurrNode4TabWR = true;                                       } else {// 针对 w:r 删除段                                               // 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 TABLE下的行节点已删除                           delFlag = true;                           break;                       } else if (delCurrNode) {//  w:p 下的节点已删除                           i--;                           delFlag = true;                           break;                       }                   }               }           }           return delFlag;       }       /**       * 针对含有表格的WORD模板, 查找及替换 w:tbl 下的标签。       * @param tblTagList : w:tbl 集合       * @param rulesValue :RuleDTO集合       * @param ns :NameSpace对象       */       @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++) {// 循环 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++) {// 循环 w:tc 取 w:p 集合                       Element tcChildren = (Element) tcTagList.get(c);                       List Element  pTagList = tcChildren.getChildren("p", ns);                       boolean delFlag = changeValue4PTag(pTagList, rulesValue,                               ns, trChildren);                       if (delFlag) {// 删除行后需要改变trChildren的指针位置                           j--;                       }                   }               }           }       }       public static void main(String[] args) throws Exception {           WordBuilder word = new WordBuilder();           Map String, String  map = new HashMap String, String            //填充参数           map.put("ToPartment", "XXX公司");           map.put("OwnerName", "张三");           map.put("CountNum", "5");           map.put("Business", "例行检查");           map.put("UsefulDays", "15");           map.put("Year", "2014");           map.put("Month", "5");           map.put("Day", "13");           map.put("ruleName", "RECOMMEND-LETTER");           Template template = word.loadRules(map);           //直接打开文件           Runtime.getRuntime().exec("explorer " + word.build(template));       }  

几点总结及注意事项:

1.  定义的元素name必须与template_rule.xml中对应相同的name的值一致,否则需要设置转换规则。

2.  模板xml中定义的占位符【※※】中的文字必须与template_rule.xml中对应的desc相同,否则需要设置转换规则.

3.  在配置好模板XML后,需要检查 w:body 标签下的子节点是否是 wx:sect 标签(与WORD版本有关),如果没有,则必须加上该标签。

4.  如果要动态删除 w:p 标签节点,则这个节点的内容需要在模板中的同一行,如果不是,则可以手动调整模板XML。

5.  如果需要实现WORD自动换行功能(关于模板中换行的方案暂没有想到更好的),则需要首先计算出对应模板该行的字数,然后采用空格填充来实现。

 


[AliFlutter]Flutter for Web在无影中的应用 无影是使用Flutter的重度用户,无论是在成熟的移动Android、iOS上,还是桌面端MacOS、Windows、还有各种硬件终端上(Linux)上都有应用 ![](https://ata2-img.oss-cn-zhangjiakou.aliyuncs.com/neweditor/c2434612-86ee-4fb6-a7d1-1622eb6d050d.png) 今年无影使用Flutt
天人合一物我相融,站点升级渐进式Web应用PWA(Progressive Web Apps)实践 PWA(Progressive web apps,渐进式 Web 应用)使用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序,说白了,PWA可以让我们的站点以原生APP的形式运行,但相比于安装原生APP应用,访问PWA显然更加容易和迅速,还可以通过链接来分享PWA应用。