我获得了一个.docx模板,我需要在我的java应用程序中填充它。最初,我打算使用Apache POI,因为在此之前,我的任务是填写一个.xlsx模板,它运行良好。但是,根据我的研究,doc4j更适合我的情况。
我的情况是这个.docx模板使用纯文本内容控件,如下所示:
现在,在检查其XML结构后,我直接在<w:sdt>
标记下的<w:p>
下看到<w:body>
。
<w:body>
...
<w:p w:rsidR="00ED05E8" w:rsidRPr="00DA4BE7" w:rsidRDefault="00AC5B37" w:rsidP="00BA6F7F">
...
<w:sdt>
<w:sdtPr>
<w:rPr>
<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
<w:i/>
<w:sz w:val="24"/>
<w:szCs w:val="24"/>
<w:u w:val="single"/>
</w:rPr>
<w:alias w:val="Name of Office/Agency Name"/>
<w:tag w:val="Name of Office/Agency Name"/>
<w:id w:val="-781645881"/>
<w:placeholder>
<w:docPart w:val="DefaultPlaceholder_-1854013440"/>
</w:placeholder>
<w:text/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:r w:rsidR="00340180" w:rsidRPr="00616BA5">
<w:rPr>
<w:rFonts w:ascii="Arial" w:hAnsi="Arial" w:cs="Arial"/>
<w:i/>
<w:sz w:val="24"/>
<w:szCs w:val="24"/>
<w:u w:val="single"/>
</w:rPr>
<w:t>(Name of Office/Agency Name)</w:t>
</w:r>
</w:sdtContent>
</w:sdt>
...
</w:body>
我想将<w:t>
的{{1}}上的文字从“(代理机构名称)”更改为另一个字符串。问题是,我不知道如何以及在这些方面之后如何坚持:
<w:sdt>
我有WordprocessingMLPackage document = WordprocessingMLPackage.load(new java.io.File(...));
MainDocumentPart mainDocument = document.getMainDocumentPart();
w:id
,但我不知道如何处理这些信息。这甚至是ContentControlsXmlEdit
sample class from the docx4j site上引用的-781645881
吗?
即使使用以下代码,我也无法获取itemId
节点:
<w:sdt>
如何更改纯文本内容控件的值?
答案 0 :(得分:0)
这个答案是我出于绝望而设计的,原因如下:
.xml
中的内容。.xml
文件的确切.docx
文件。storeItemid
文件的.xml
找不到.docx
。这是我用.groovy
编写的实用工具类:
import javax.xml.bind.JAXBElement
import org.apache.poi.openxml4j.exceptions.InvalidFormatException
import org.docx4j.openpackaging.packages.WordprocessingMLPackage
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart
import org.docx4j.wml.CTBookmark
import org.docx4j.wml.P
import org.docx4j.wml.R
import org.docx4j.wml.SdtBlock
import org.docx4j.wml.SdtContent
import org.docx4j.wml.SdtRun
import org.docx4j.wml.Text
class WordReport {
private WordprocessingMLPackage document
private Map<String, String> contentControlMapping
private Map<String, Object> reportArgs
public WordReport(Map<String, Object> reportArgs) {
document = WordprocessingMLPackage.createPackage()
this.reportArgs = reportArgs
}
public WordprocessingMLPackage exportReport() {
return document
}
private String getNewMapping(String contentControlText) {
return contentControlMapping.get(contentControlText)
}
private boolean isMapped(String contentControlText) {
return contentControlMapping.containsKey(contentControlText)
}
protected void mapNewMapping() {
MainDocumentPart mainDocument = document.getMainDocumentPart()
List<Object> nodes = mainDocument.getJAXBNodesViaXPath("//w:sdt", false)
String key
SdtContent content
nodes.each { n ->
if(n instanceof SdtBlock) {
content = n.getSdtContent()
}
else if(n instanceof JAXBElement) {
if(n.getValue() instanceof SdtRun) {
content = n.getValue().getSdtContent()
}
}
content.getContent().each { sdtcc ->
if(sdtcc instanceof P) {
sdtcc.getContent().each { pc ->
pc.getContent().each { rc ->
println "rc.getValue().getClass(): " + rc.getValue().getClass()
if(rc.getValue() instanceof Text) {
key = rc.getValue().getValue()
isMapped(key) ? rc.getValue().setValue(getNewMapping(key)) : null
}
else if(rc.getValue() instanceof R) {
rc.getValue().getContent().each { rrc ->
if(rrc instanceof JAXBElement) {
key = rrc.getValue().getValue()
isMapped(key) ? rrc.getValue().setValue(getNewMapping(key)) : null
}
}
}
}
}
}
else if(sdtcc instanceof R) {
sdtcc.getContent().each { rc ->
if(rc instanceof JAXBElement) {
key = rc.getValue().getValue()
isMapped(key) ? rc.getValue().setValue(getNewMapping(key)) : null
}
}
}
else if(sdtcc instanceof JAXBElement) {
if(sdtcc.getValue() instanceof CTBookmark) {
}
else if(sdtcc.getValue() instanceof JAXBElement) {
key = sdtcc.getValue().getValue()
isMapped(key) ? sdtcc.getValue().setValue(getNewMapping(key)) : null
}
}
}
}
}
public void setMapping(Map contentControlMapping) {
this.contentControlMapping = contentControlMapping
}
}
此类的核心部分是mapNewMapping()
方法。基本上它的作用是将contentControlMapping
变量上的映射映射到<w:t>
内的任何<w:sdt>
,无论它是直接在<w:sdt>
下还是在<w:rPr>
下。在<w:sdt>
等内部。我使用getJAXBNodesViaXPath()
方法检索所有P
的列表。
此限制是,这只能支持R
,CTBookmark
,SdtBlock
,SdtContent
,SdtRun
,{{1}的有限组合}}。如果在我未预料到的复杂或深嵌套<w:t>
内找到.xml
,则不会映射它。这就是为什么我提到我已经先阅读了.xml
文件的.docx
。