얼마 전 웹 애플리케이션에서 자동으로 Word를 생성해 달라는 요청을 받았습니다. 이제 공유할 몇 가지 주요 단계를 컴파일했습니다.
아이디어: (참고: 이는 WORD2003 버전에만 해당되며 다른 버전도 유사합니다.)
WORD 파일의 내부 데이터 및 형식이 XML 파일 형식으로 저장되므로 WORD 파일을 DOC에서 XML 형식으로 쉽게 변환할 수 있으며 XML 파일 조작이 훨씬 편리해 다양한 플랫폼 독립적인 작업과의 통합을 실현합니다. 노드 쿼리, 교체, 삭제, 추가 등을 통해 Word 파일을 생성합니다. 따라서 템플릿을 기반으로 WORD 파일을 생성하는 과정의 핵심은 XML 파일의 특수 태그를 사용자 데이터로 대체한 후 DOC 파일로 저장하는 과정이다.
관련된 주요 단계는 다음과 같습니다(소개서를 예로 들어).
1단계: 필요에 따라 WORD 템플릿 만들기
DOC 형식의 새 WORD 파일을 생성하고 필요에 따라 템플릿 내용을 채운 다음 글꼴, 스타일, 빈 줄 등을 포함하여 템플릿 형식을 설정합니다. 특수 태그(예: [※Unit Name※])를 사용하여 비트를 채워야 할 데이터를 미리 점유한 후 새로 생성된 WORD 파일을 XML 형식의 파일로 저장합니다. 이로써 WORD 템플릿이 완성되었으며, 코드는 다음과 같습니다.
template-rule.xml이라는 새 구성 파일을 추가합니다. 각 템플릿 노드는 템플릿 유형에 해당합니다. 각 템플릿에는 태그 목록 노드가 있습니다. 이 노드에 포함된 모든 하위 노드에는 템플릿에서 대체되거나 삭제될 모든 노드에 대한 정보가 포함됩니다. 노드 값, 노드 속성 영어 이름, 중국어 설명, 필드 유형, 삭제 가능 여부 등 이 구성 파일을 설정할 때 desc 속성의 값은 템플릿 XML의 자리 표시자와 일치해야 한다는 점에 유의해야 합니다. 예를 들어 템플릿 XML에 설정된 연도 입력 항목 [※연도※]는 template-rule.xml의 desc="연도" 이름과 일치해야 합니다. 코드는 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
<!--?xml version="1.0" 인코딩="GB2312"?-->
<!-- 템플릿 정의-->
<템플릿>
<!-- 설명: S-문자열; E-금액; M-대문자 금액; ifEmptyDelete: 상위 노드를 삭제하려면 T-값이 비어 있습니다. -->
<template name="RECOMMEND-LETTER" desc="소개서" templatefile="template4.xml">
<taglist comment="단일 값 태그 목록">
<tag id="1" name="ToPartment" desc="수신 부서" type="S" ifemptydelete="T">#ToPartment</tag><!--수신 부서-->
<tag id="2" name="OwnerName" desc="Name" type="S">#OwnerName</tag><!--이름-->
<tag id="3" name="CountNum" desc="인원" type="S">#CountNum</tag><!--인원-->
<tag id="4" name="비즈니스" desc="Content" type="S">#비즈니스</tag><!--Content-->
<tag id="5" name="UsefulDays" desc="유효 기간" type="S">#UsefulDays</tag><!--유효 기간-->
<tag id="6" name="연도" desc="연도" type="S">#연도</tag><!--연도-->
<tag id="7" name="월" desc="month" type="S">#월</tag><!--month-->
<tag id="8" name="Day" desc="日" type="S">#Day</tag><!--Day-->
</태그목록>
</템플릿>
</템플릿>
3단계: 자바 코드 작성
다음과 같이 코드 코드를 복사합니다.
/**
* 매개변수 및 규칙
*/
공개 클래스 RuleDTO {
/**
* 태그 이름
*/
개인 문자열 parmName;
/**
* 태그 설명
*/
개인 문자열 parmDesc;
/**
* 태그 일련번호
*/
개인 문자열 parmSeq;
/**
* 태그 값 유형
*/
개인 문자열 parmType;
/**
* 태그 매개변수 이름
*/
개인 문자열 parmRegular;
/**
* 태그 값
*/
개인 문자열 parmValue;
/**
* 태그 값이 비어 있으면 이 속성을 삭제하세요.
*/
개인 문자열 ifEmptyDelete;
}
다음과 같이 코드 코드를 복사합니다.
/**
* 설명 : 워드 템플릿 정보
*/
공개 클래스 템플릿 {
개인 문자열 이름;//템플릿 이름
개인 문자열 설명;//템플릿 설명
개인 문자열 templateFile;//템플릿 파일
private Vector<ruledto> 규칙;//템플릿 규칙
}</ruledto>
다음과 같이 코드 코드를 복사합니다.
공개 클래스 WordBuilder {
/**
* 템플릿을 기반으로 한 교체 규칙 읽기
* @param templateName 템플릿 ID
*/
@SuppressWarnings("선택 해제됨")
공개 템플릿 loadRules(Map<string, string=""> ruleValue) {
입력스트림 = null;
템플릿 템플릿 = 새 템플릿();
// 규칙 구성 파일 경로
문자열 ruleFile = "template-rule.xml";
// 템플릿 규칙 이름
문자열 templateRuleName = "";
노력하다 {
templateRuleName = ruleValue.get("ruleName");
//템플릿 규칙 파일 읽기
in = this.getClass().getClassLoader().getResourceAsStream(ruleFile);
// 템플릿 규칙을 구문 분석합니다.
SAXBuilder sb = new SAXBuilder();
문서 문서 = sb.build(in);
Element root = doc.getRootElement(); // 루트 요소를 가져옵니다.
List<element> templateList = root.getChildren();//모든 템플릿 구성
요소 요소 = null;
Vector<ruledto> 규칙 = null;
for (int i = 0; i < templateList.size(); i++) {// 모든 템플릿 탐색
요소 = (요소) templateList.get(i);
String templateName = element.getAttributeValue("name");
if (templateRuleName.equalsIgnoreCase(templateName)) {//주어진 템플릿 구성 찾기
template.setName(템플릿이름);
template.setDesc(element.getAttributeValue("desc"));
template.setTemplateFile(요소
.getAttributeValue("templateFile"));
List<element> tagList = ((요소) element.getChildren()
.get(0)).getChildren(); // 태그 목록
요소 태그 = null;
RuleDTO ruleDTO = null;
규칙 = 새로운 Vector<ruledto>();
for (int j = 0; j < tagList.size(); j++) {
태그 = (요소) tagList.get(j);
ruleDTO = 새로운 RuleDTO();
ruleDTO.setParmName(tag.getAttributeValue("name"));
ruleDTO.setParmDesc("【※"
+ tag.getAttributeValue("desc") + "※】");
ruleDTO.setParmSeq(tag.getAttributeValue("id"));
ruleDTO.setParmType(tag.getAttributeValue("type"));
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(value);
규칙.추가(ruleDTO);
}
template.setRules(rules);
부서지다;
}
}
} 잡기(FileNotFoundException e) {
e.printStackTrace();
} 잡기(JDOMException e) {
e.printStackTrace();
} 잡기(IOException e) {
e.printStackTrace();
} 마지막으로 {
노력하다 {
넣다();
} 잡기(예외 e) {
e.printStackTrace();
}
}
반환 템플릿;
}
/**
* 부모 노드 찾기
*/
공개 요소 findElement(요소 currNode, 문자열 parentNodeId) {
//노드가 비어 있음으로 표시됨
if (currNode == null || parentNodeId == null) {
null을 반환;
}
요소 pNode = null;
하다 {
pNode = currNode.getParent();
currNode = pNode;
} while (parentNodeId.equalsIgnoreCase(pNode.getName()));
pNode를 반환합니다.
}
/**
* 워드 파일 생성
*/
@SuppressWarnings("선택 해제됨")
공개 문자열 빌드(템플릿 템플릿) {
입력스트림 = null;
OutputStream fo = null;
//생성된 파일의 경로
문자열 파일 = "d://test//" + template.getDesc() + ".doc";
노력하다 {
//템플릿 파일 읽기
in = this.getClass().getClassLoader()
.getResourceAsStream(template.getTemplateFile());
SAXBuilder sb = new SAXBuilder();
문서 문서 = sb.build(in);
Element root = doc.getRootElement(); // 루트 요소를 가져옵니다.
네임스페이스 ns = root.getNamespace();// 네임스페이스
// <wx:sect> 요소는 word 03 템플릿에 존재합니다.
List<element> sectList = root.getChild("body", ns).getChildren();
요소 sectElement = (요소) sectList.get(0);
// <w:p> 아래의 태그 모음
List<요소> pTagList = sectElement.getChildren("p", ns);
// <w:tbl> 아래의 태그 모음
List<요소> 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(파일);
outp.output(doc, fo);
} 잡기(FileNotFoundException e) {
e.printStackTrace();
} 잡기(JDOMException e) {
e.printStackTrace();
} 잡기(IOException e) {
e.printStackTrace();
} 마지막으로 {
노력하다 {
넣다();
fo.close();
} 잡기(예외 e) {
e.printStackTrace();
}
}
파일 반환;
}
/**
* <w:body><wx:sect><w:p> 수준의 WORD 템플릿의 경우 <w:p> 아래에서 태그를 찾아서 바꿉니다.
* @param pTagList:<w:p>컬렉션
* @param ruleValue: RuleDTO 컬렉션
* @param ns: NameSpace 객체
* @param trChildren: <w:tbl>의 하위 노드 <w:tr> 모음
*/
@SuppressWarnings("선택 해제됨")
개인 부울 ChangeValue4PTag(List<element> pTagList,
Vector<ruledto> ruleValue, 네임스페이스 ns, List<element> trChildren) {
요소 p = null;
부울 delFlag = false;
for (int i = 0; i < pTagList.size(); i++) {
boolean delCurrNode = false;//현재 노드 삭제
boolean delCurrNode4TabWR = false;//테이블에서 단일 행 노드 삭제
p = (요소) pTagList.get(i);
List<요소> pChild = p.getChildren("r", ns);
for (int j = 0; pChild != null && j < pChild.size(); j++) {
요소 pChildren = (요소) pChild.get(j);
요소 t = pChildren.getChild("t", ns);
if (t != null) {
문자열 텍스트 = 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>에 대해 이 행을 삭제합니다.
요소 요소 = ((요소) p
.getParent()).getParent();
trChildren.remove(요소);
delCurrNode4TabWR = 참;
} else {//<w:r>에 대한 세그먼트 삭제
// pTagList.remove(p);
pTagList.remove(pChildren);
delCurrNode = true;
}
부서지다;
} 또 다른 {
텍스트 = text.replaceAll(dto.getParmDesc()
.trim(), dto.getParmValue());
}
}
}
t.setText(text);
}
if (delCurrNode4TabWR) {// <w:tbl>TABLE 아래의 행 노드가 삭제되었습니다.
delFlag = 사실;
부서지다;
} else if (delCurrNode) {// <w:p> 아래의 노드가 삭제되었습니다.
나--;
delFlag = 사실;
부서지다;
}
}
}
}
delFlag를 반환합니다.
}
/**
* 테이블이 포함된 WORD 템플릿의 경우 <w:tbl>에서 태그를 찾아 교체하세요.
* @param tblTagList:<w:tbl> 컬렉션
* @param ruleValue: RuleDTO 컬렉션
* @param ns: NameSpace 객체
*/
@SuppressWarnings("선택 해제됨")
개인 무효 변경 Value4TblTag(목록<요소> tblTagList,
벡터<ruledto> 규칙값, 네임스페이스 ns) {
요소 p = null;
for (int i = 0; tblTagList != null && i < tblTagList.size(); i++) {
p = (요소) tblTagList.get(i);
List<요소> trChildren = p.getChildren("tr", ns);
for (int j = 0; trChildren != null && j < trChildren.size(); j++) {// 루프<w:tr>
요소 pChildren = (요소) trChildren.get(j);
List<요소> tcTagList = pChildren.getChildren("tc", ns);
for (int c = 0; tcTagList != null && c < tcTagList.size(); c++) {// <w:tc>를 반복하여 <w:p> 컬렉션을 가져옵니다.
요소 tcChildren = (요소) tcTagList.get(c);
List<요소> pTagList = tcChildren.getChildren("p", ns);
부울 delFlag =changeValue4PTag(pTagList, ruleValue,
ns, trChildren);
if (delFlag) {// 행을 삭제한 후 trChildren의 포인터 위치를 변경해야 합니다.
j--;
}
}
}
}
}
public static void main(String[] args)에서 예외가 발생합니다.
WordBuilder 단어 = new WordBuilder();
Map<string, string=""> map = new HashMap<string, string="">();
//매개변수 채우기
map.put("ToPartment", "XXX 회사");
map.put("OwnerName", "장산");
map.put("CountNum", "5");
map.put("비즈니스", "일상 점검");
map.put("UsefulDays", "15");
map.put("연도", "2014");
map.put("월", "5");
map.put("일", "13");
map.put("ruleName", "RECOMMEND-LETTER");
템플릿 template = word.loadRules(map);
//파일을 직접 엽니다.
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의 자동 줄 바꿈 기능을 구현해야 하는 경우(템플릿의 줄 바꿈에 대한 더 나은 솔루션은 아직 없음) 먼저 템플릿의 해당 줄에 있는 단어 수를 계산한 다음 공백 채우기를 사용해야 합니다. 그것을 달성하기 위해.