Некоторое время назад я получил запрос на веб-приложение для автоматического создания Word. Теперь я собрал некоторые ключевые шаги, которыми хочу поделиться.
Идея: (Примечание: это только для версии WORD2003, другие версии аналогичны.)
Поскольку внутренние данные и формат файлов WORD хранятся в виде файлов XML, файлы WORD можно легко конвертировать из формата DOC в формат XML, и работать с файлами XML гораздо удобнее, что обеспечивает интеграцию с различными операциями, независимыми от платформы. генерировать файлы Word посредством запроса узла, замены, удаления, добавления и т. д. Поэтому суть создания WORD-файла на основе шаблона заключается в процессе замены специальных тегов в XML-файле пользовательскими данными и последующем сохранении его в виде DOC-файла.
Вот некоторые из ключевых шагов (на примере рекомендательного письма):
Шаг первый: Создайте шаблон WORD в соответствии с вашими потребностями.
Создайте новый файл WORD в формате DOC, заполните содержимое шаблона по мере необходимости и задайте формат шаблона, включая шрифты, стили, пустые строки и т. д. Используйте специальные теги (например: [※Имя блока※]), чтобы предварительно заполните бит данных, который необходимо заполнить, а затем сохраните вновь созданный файл WORD в формате XML. На этом шаблон WORD завершен, код следующий:
Добавьте новый файл конфигурации с именем template-rule.xml, каждый узел шаблона соответствует типу шаблона. В каждом шаблоне есть узел списка тегов. Все дочерние узлы, содержащиеся в этом узле, содержат информацию обо всех узлах, которые будут заменены или удалены в шаблоне. Информация об узле включает в себя: значение узла, английское имя атрибута узла, описание на китайском языке, тип поля. можно ли его удалить и т.д. При настройке этого файла конфигурации необходимо учитывать, что значение атрибута desc должно соответствовать заполнителю в XML-шаблоне. Например: элемент ввода года [※Year※], установленный в XML-шаблоне, должен соответствовать имени desc="Year" в template-rule.xml. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
<!--?xml version="1.0"coding="GB2312"?-->
<!-- Определение шаблона-->
<шаблоны>
<!-- Описание: S-строка; D-количество; M-прописная сумма; ifEmptyDelete: T-значение пусто для удаления родительского узла, значение по умолчанию — F -->
<template name="RECOMMEND-LETTER" desc="Рекомендательное письмо" templatefile="template4.xml">
<taglist примечание="Список тегов с одним значением">
<tag id="1" name="ToPartment" desc="Принимающий отдел" type="S" ifemptydelete="T">#ToPartment</tag><!--Приемный отдел-->
<tag id="2" name="OwnerName" desc="Name" type="S">#OwnerName</tag><!--Name-->
<tag id="3" name="CountNum" desc="Количество людей" type="S">#CountNum</tag><!--Количество людей-->
<tag id="4" name="Business" desc="Content" type="S">#Business</tag><!--Content-->
<tag id="5" name="UsefulDays" desc="Период действия" type="S">#UsefulDays</tag><!--Срок действия-->
<tag id="6" name="Год" desc="год" type="S">#Год</tag><!--year-->
<tag id="7" name="Месяц" desc="месяц" type="S">#Месяц</tag><!--месяц-->
<tag id="8" name="День" desc="日" type="S">#День</tag><!--День-->
</теглист>
</шаблон>
</шаблоны>
Шаг 3. Напишите Java-код.
Скопируйте код кода следующим образом:
/**
* Параметры и правила
*/
общественный класс RuleDTO {
/**
* имя тега
*/
частная строка parmName;
/**
* описание тега
*/
частная строка parmDesc;
/**
* серийный номер бирки
*/
частная строка parmSeq;
/**
* тип значения тега
*/
частная строка parmType;
/**
* имя параметра тега
*/
частная строка parmRegular;
/**
* значение тега
*/
частная строка parmValue;
/**
* Если значение тега пустое, удалите этот атрибут.
*/
частная строка ifEmptyDelete;
}
Скопируйте код кода следующим образом:
/**
* Описание: информация о шаблоне Word.
*/
Шаблон публичного класса {
имя частной строки;//имя шаблона
Private String desc;//описание шаблона
частная строка templateFile;//файл шаблона
частные правила Vector<ruledto>;//правила шаблона
</ruledto>
Скопируйте код кода следующим образом:
публичный класс WordBuilder {
/**
* Чтение правил замены на основе шаблона
* @param templateName Идентификатор шаблона
*/
@SuppressWarnings («не отмечено»)
общедоступный шаблон loadRules(Map<string, string=""> ruleValue) {
Входной поток в = ноль;
Шаблон шаблона = новый шаблон();
// Путь к файлу конфигурации правила
Строка ruleFile = "шаблон-правило.xml";
// Имя правила шаблона
Строка templateRuleName = "";
пытаться {
templateRuleName = ruleValue.get("ruleName");
//Читаем файл правил шаблона
in = this.getClass().getClassLoader().getResourceAsStream(ruleFile);
// Разбираем правила шаблона
SAXBuilder sb = новый SAXBuilder();
Документ документа = sb.build(in);
Корень элемента = doc.getRootElement() // Получаем корневой элемент
List<element> templateList = root.getChildren();//Все конфигурации шаблона
Элемент element = null;
Правила Vector<ruledto> = null;
for (int i = 0; i < templateList.size(); i++) {// Обход всех шаблонов
элемент = (Элемент) templateList.get(i);
Строка templateName = element.getAttributeValue("name");
if (templateRuleName.equalsIgnoreCase(templateName)) {//Найти данную конфигурацию шаблона
template.setName(имяшаблона);
template.setDesc(element.getAttributeValue("desc"));
template.setTemplateFile(элемент
.getAttributeValue("templateFile"));
List<element> tagList = ((Element) element.getChildren()
.get(0)).getChildren(); // список тегов
Тег элемента = ноль;
RuleDTO ruleDTO = ноль;
правила = новый Vector<ruledto>();
for (int j = 0; j < tagList.size(); j++) {
тег = (Элемент) tagList.get(j);
ruleDTO = новое RuleDTO();
ruleDTO.setParmName(tag.getAttributeValue("имя"));
ruleDTO.setParmDesc("【※"
+ tag.getAttributeValue("desc") + "※】");
ruleDTO.setParmSeq(tag.getAttributeValue("id"));
ruleDTO.setParmType(tag.getAttributeValue("тип"));
if ("T".equalsIgnoreCase(тег
.getAttributeValue("ifEmptyDelete"))) {// Можно ли удалить отметку
ruleDTO.setIfEmptyDelete("T");
} еще {
ruleDTO.setIfEmptyDelete("F");
}
ruleDTO.setParmRegular(tag.getText());
// ценить
// Определяем тип параметра
Строковое значение = (String) ((Map<string, string="">) ruleValue)
.get(ruleDTO.getParmRegular().replaceAll("#",
""));
ruleDTO.setParmValue(значение);
правила.добавить(правилоDTO);
}
шаблон.setRules(правила);
перерыв;
}
}
} catch (FileNotFoundException e) {
е.printStackTrace();
} catch (JDOMException e) {
е.printStackTrace();
} catch (IOException e) {
е.printStackTrace();
} окончательно {
пытаться {
в.закрыть();
} catch (Исключение е) {
е.printStackTrace();
}
}
шаблон возврата;
}
/**
* Найдите родительский узел
*/
общедоступный элемент findElement (Элемент currNode, String родительскийNodeId) {
//Узел помечен как пустой
if (currNode == null || родительскийNodeId == null) {
вернуть ноль;
}
Элемент pNode = ноль;
делать {
pNode = currNode.getParent();
currNode = pNode;
} while (parentNodeId.equalsIgnoreCase(pNode.getName()));
вернуть pNode;
}
/**
* Создать файл Word
*/
@SuppressWarnings («не отмечено»)
общедоступная строка build (шаблон шаблона) {
Входной поток в = ноль;
OutputStream fo = null;
//Путь к сгенерированному файлу
Строковый файл = "d://test//" + template.getDesc() + ".doc";
пытаться {
//Читаем файл шаблона
в = this.getClass().getClassLoader()
.getResourceAsStream(template.getTemplateFile());
SAXBuilder sb = новый SAXBuilder();
Документ документа = sb.build(in);
Корень элемента = doc.getRootElement() // Получаем корневой элемент
Пространство имен ns = root.getNamespace();// NameSpace
// Элемент <wx:sect> существует в шаблоне слова 03
List<element> sectList = root.getChild("body", ns).getChildren();
Элемент sectElement = (Элемент) 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 = новый XMLOutputter(" ", true, "UTF-8");
fo = новый FileOutputStream (файл);
outp.output(док, фо);
} catch (FileNotFoundException e) {
е.printStackTrace();
} catch (JDOMException e) {
е.printStackTrace();
} catch (IOException e) {
е.printStackTrace();
} окончательно {
пытаться {
в.закрыть();
фо.закрыть();
} catch (Исключение е) {
е.printStackTrace();
}
}
возвратный файл;
}
/**
* Для шаблонов WORD уровня <w:body><wx:sect><w:p> найдите и замените теги в <w:p>.
* @param pTagList:<w:p>collection
* @param RulesValue: коллекция RuleDTO.
* @param ns: объект NameSpace
* @param trChildren: коллекция дочерних узлов <w:tr> из <w:tbl>
*/
@SuppressWarnings («не отмечено»)
частное логическое значениеchangeValue4PTag(List<element> pTagList,
Vector<ruledto> RulesValue, Namespace ns, List<element> trChildren) {
Элемент p = ноль;
логическое значение delFlag = ложь;
for (int i = 0; i < pTagList.size(); i++) {
boolean delCurrNode = false;//Удалить текущий узел
boolean delCurrNode4TabWR = false;//Удалить один узел строки в таблице
p = (Элемент) pTagList.get(i);
List<element> pChild = p.getChildren("r", ns);
for (int j = 0; pChild != null && j < pChild.size(); j++) {
Элемент pChildren = (Элемент) pChild.get(j);
Элемент t = pChildren.getChild("t", ns);
если (т != ноль) {
Строковый текст = t.getTextTrim();
if (text.indexOf("【※") != -1) {
for (int v = 0; v < ruleValue.size(); v++) {
RuleDTO dto = (RuleDTO) ruleValue.get(v);
if (text.indexOf(dto.getParmDesc().trim()) != -1) {
// Определяем, является ли значение атрибута нулевым для удаления
if ("T".equals(dto.getIfEmptyDelete())
&& StringUtils.isBlank(dto
.getParmValue())) {
//Удаляем верхний узел этого узла
текст = "";
if (trChildren != null) {//Удалить эту строку для <w:tbl>
Элемент element = ((Элемент) p
.getParent()).getParent();
trChildren.remove(элемент);
delCurrNode4TabWR = правда;
} else {//Удалить сегмент для <w:r>
// pTagList.remove(p);
pTagList.remove(pChildren);
delCurrNode = правда;
}
перерыв;
} еще {
текст = text.replaceAll(dto.getParmDesc()
.trim(), dto.getParmValue());
}
}
}
т.setText(текст);
}
if (delCurrNode4TabWR) {// <w:tbl>Узел строки в таблице TABLE был удален
дельФлаг = правда;
перерыв;
} else if (delCurrNode) {// Узел под <w:p> был удален
я--;
дельФлаг = правда;
перерыв;
}
}
}
}
вернуть delFlag;
}
/**
* Для шаблонов WORD, содержащих таблицы, найдите и замените теги в <w:tbl>.
* Коллекция @param tblTagList:<w:tbl>
* @param RulesValue: коллекция RuleDTO.
* @param ns: объект NameSpace
*/
@SuppressWarnings («не отмечено»)
Private void ChangeValue4TblTag(List<element> tblTagList,
Vector<ruledto> ruleValue, пространство имен ns) {
Элемент p = ноль;
for (int i = 0; tblTagList != null && i < tblTagList.size(); i++) {
p = (Элемент) tblTagList.get(i);
List<element> trChildren = p.getChildren("tr", ns);
for (int j = 0; trChildren != null && j < trChildren.size(); j++) {// Loop<w:tr>
Элемент pChildren = (Элемент) trChildren.get(j);
List<element> tcTagList = pChildren.getChildren("tc", ns);
for (int c = 0; tcTagList != null && c < tcTagList.size(); c++) {// Цикл <w:tc> для получения коллекции <w:p>
Элемент tcChildren = (Элемент) tcTagList.get(c);
List<element> pTagList = tcChildren.getChildren("p", ns);
логическое значение delFlag = ChangeValue4PTag(pTagList, RulesValue,
нс, trChildren);
if (delFlag) {// После удаления строки необходимо изменить положение указателя trChildren
дж--;
}
}
}
}
}
public static void main(String[] args) выдает исключение {
Слово WordBuilder = новый WordBuilder();
Map<string, string=""> map = new HashMap<string, string="">();
//заполняем параметры
map.put("ToPartment", "Компания ХХХ");
map.put("Имявладельца", "Чжан Сан");
map.put("CountNum", "5");
map.put("Бизнес", "Регулярная проверка");
map.put("ПолезныеДни", "15");
map.put("Год", "2014");
map.put("Месяц", "5");
map.put("День", "13");
map.put("имяправила", "РЕКОМЕНДУЮЩАЯ-БУКВА");
Шаблон шаблона = word.loadRules(карта);
//Открываем файл напрямую
Runtime.getRuntime().exec("проводник" + word.build(шаблон));
}
</string,></string,></element></w:p></w:tc></element></w:tr></element></ruledto></element>< /w:tbl></w:tbl></w:p></w:tbl></w:r></w:tbl></element></element></ruledto></ele ment></w:tr></w:tbl></w:p></w:p></w:p></wx:sect></w:body></element></ w:tbl></element></w:p></element></wx:sect></string,></ruledto></element></ruledto></element></string,>
Шаг 4: Готово
Некоторые итоговые положения и примечания:
1. Определенное имя элемента должно соответствовать значению, соответствующему тому же имени в template_rule.xml, в противном случае необходимо установить правило преобразования.
2. Текст в заполнителе [※※], определенном в XML-шаблоне, должен совпадать с соответствующим описанием в template_rule.xml, в противном случае необходимо установить правило преобразования.
3. После настройки XML-шаблона необходимо проверить, является ли дочерний узел под меткой меткой (связанной с версией WORD). Если нет, метку необходимо добавить.
4. Если вы хотите динамически удалить узел метки, содержимое этого узла должно находиться в одной строке шаблона. В противном случае вы можете вручную настроить XML-файл шаблона.
5. Если вам нужно реализовать функцию автоматического переноса строк WORD (лучшего решения для переноса строк в шаблонах пока нет), вам нужно сначала посчитать количество слов в соответствующей строке шаблона, а затем использовать заполнение пробелов чтобы достичь этого.