我正在使用docx4j将Word模板转换为多个HTML文件,每章一个。
Word模板有几个由多个字段(DOCPROPERTY ...
)映射的自定义属性,表示为简单字段和复杂字段。当word文档转换为HTML(如${...}
或[@... /]
指令)时,我会填充这些属性以获取Freemarker代码。
在后面的步骤中,我会查找“标题1”段落以识别章节,然后在转换前将文档拆分为多个Word文档,然后将这些文档转换为HTML并写入临时文件。
每个文档都已成功转换为HTML并且字段被我的标记正确替换,但在写入页眉和页脚部分时表现错误:字段代码在字段值(例如DOCPROPERTY "PROPERTY_NAME" \* MERGEFORMAT ${constants['PROPERTY_NAME']}
)之前写入而不是字段仅限值(例如${constants['PROPERTY_NAME']}
)。
如果我将更新的文档写入docx文件,则生成的文档似乎没有任何错误。
如果它对解决问题很有用,那就是我分割文件的方法(每章):
(实际上我每次都不使用克隆方法,但是我将更新后的文档写入ByteArrayOutputStream,然后根据克隆方法的来源为每一章读取它。)
我怀疑这是一个docx4j错误,其他人是否尝试过类似的东西?
最后这些是我的平台细节:
提前感谢您提供任何帮助
修改
要生成freemarker标记来代替Word字段,我按如下方式设置文档属性值:
new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(), visitor);
的简单或复杂字段,其中visitor
是我查找字段和设置属性的自定义回调遍历我寻找的文件
FldChar
个类型为BEGIN的元素,并使用FieldsPreprocessor.canonicalise((P) ((R) fc.getParent()).getParent(), fields);
解析它们(我不使用canonicalise
的返回值)fc
找到FldChar
ArrayList<FieldRef>
}和字段为空CTSimpleField
;然后我提取并解析字段的instrText属性FldSimpleModel fldSimpleModel = new FldSimpleModel(); fldSimpleModel.build((CTSimpleField) o, null);
个元素并使用fldSimpleModel.getFldArgument()
解析它们;然后我使用wordMLPackage.getDocPropsCustomPart().setProperty(propertyName, finalValue);
获取属性名称List<Relationship> rels = wordMLPackage.getMainDocumentPart().getRelationshipsPart().getRelationships().getRelationship();
for (Relationship rel : rels) {
Part p = wordMLPackage.getMainDocumentPart().getRelationshipsPart().getPart(rel);
if (p == null) {
continue;
}
if (p instanceof ContentAccessor) {
new TraversalUtil(((ContentAccessor) p).getContent(), visitor);
}
}
最后我从第1步开始对页眉和页脚执行相同的操作,如下所示:
FieldUpdater updater = new FieldUpdater(wordMLPackage);
try {
updater.update(true);
} catch (Docx4JException ex) {
Logger.getLogger(WorkerDocx4J.class.getName()).log(Level.SEVERE, null, ex);
}
最后我更新字段如下
HTMLSettings settings = Docx4J.createHTMLSettings();
settings.setWmlPackage(wordDoc);
settings.setImageHandler(new InlineImageHandler(myDataModel));
Docx4jProperties.setProperty("docx4j.Convert.Out.HTML.OutputMethodXML", true);
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write("[#ftl]\r\n".getBytes("UTF-8"));
Docx4J.toHTML(settings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);
String template = new String(os.toByteArray(), "UTF-8");
填写所有字段属性后,我按照前面的描述克隆文档,并使用
转换过滤后的克隆实例template
然后我在<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadCertificateFileName</key>
<string>pkiclient.exe.cer</string>
<key>PayloadContent</key>
<data>
MIIDWzCCAkOgAwIBAgIIbbXoNrXgWrUwDQYJKoZIhvcNAQELBQAw
OzEVMBMGA1UEAwwMTWFuYWdlbWVudENBMRUwEwYDVQQKDAxFSkJD
QSBTYW1wbGUxCzAJBgNVBAYTAlNFMB4XDTE1MDYwOTExMTQzN1oX
DTI1MDYwNjExMTQzN1owOzEVMBMGA1UEAwwMTWFuYWdlbWVudENB
MRUwEwYDVQQKDAxFSkJDQSBTYW1wbGUxCzAJBgNVBAYTAlNFMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA41riRAQHXODW
w8ihGSmf/OYByA4z0fQHLdTPzcu3fg0wvY72b74Hwo4DHEtna8I+
ZQ0y16vx1y/RBQR7KWJR5NkKK+mdtxdlp4Ef7IrPBAg4donT8h7I
S7/AMA8KEzzCza0nhK+lWejtLaWSnjVZ60nz/6R/kLn2chWOHFga
9JOdB7dPovv27eBE5+08xmRfzc5bguqVslcDcW6xLfkR3ChhXn7L
C2V9DR+y3J+Tjo/iWkyJH3XAe+jHh8gpGvMroolm7axKSDEKl0PD
LR2AYxrMDYpR70m6aMKs/q2dlbykCzDwLhXGxDmjcxyZU/cqyXMZ
5BEHI+7hSFGyXlv6tQIDAQABo2MwYTAdBgNVHQ4EFgQUtUUcq/GH
iBHrkanRtz4Y6EnWSocwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
GDAWgBS1RRyr8YeIEeuRqdG3PhjoSdZKhzAOBgNVHQ8BAf8EBAMC
AYYwDQYJKoZIhvcNAQELBQADggEBAMZMwmp5+YemWxnvWI4dw9Hz
rnzuI4It2HLDnCTE7GDrE8TI3lb+ZNxuuK7NKr0IgIQsuZzEiRCb
oq2OWnGXLvvqq5F0EybdiYCLU1E1OjqqQlOW9wWHB35PZUb6tQi2
hCoafFy9CUDLcRS95I0Og7rbszFZAcQrKpyF+qSRAFcrD6O1JCSk
ad+giQBsfD/erRFPd7mVHVjm5O+T8Sz8LL5MgI7decRhjfADVW16
ZWdajhgBnmeW+KTnOJfEMjqMmU6JeSl26rbSqcWR28Or2smXkRkX
LUA8j/B3FbUTQ+MOSJSj+rl54f0iAs4Tzey7Pgh7D2rtgrjM4M3M
0iky3FM=
</data>
<key>PayloadDescription</key>
<string>Configures certificate settings.</string>
<key>PayloadDisplayName</key>
<string>ManagementCA</string>
<key>PayloadIdentifier</key>
<string>com.apple.security.root.43EA4618-C9DF-439E-A346-C4CCDD73FAA6</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadUUID</key>
<string>43EA4618-C9DF-439E-A346-C4CCDD73FAA6</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
<dict>
<key>PayloadContent</key>
<dict>
<key>CAFingerprint</key>
<data>
</data>
<key>Challenge</key>
<string>Password1</string>
<key>Key Type</key>
<string>RSA</string>
<key>Keysize</key>
<integer>2048</integer>
<key>Subject</key>
<array>
<array>
<array>
<string>CN</string>
<string>150615987102</string>
</array>
</array>
</array>
<key>URL</key>
<string>http://172.20.16.158:8080/ejbca/publicweb/apply/scep/testSCEP/pkiclient.exe</string>
</dict>
<key>PayloadDescription</key>
<string>Configures SCEP settings</string>
<key>PayloadDisplayName</key>
<string>SCEP</string>
<key>PayloadIdentifier</key>
<string>com.apple.security.scep.FC189619-2F84-4E39-AE66-5E037D8A8A84</string>
<key>PayloadType</key>
<string>com.apple.security.scep</string>
<key>PayloadUUID</key>
<string>FC189619-2F84-4E39-AE66-5E037D8A8A84</string>
<key>PayloadVersion</key>
<real>1</real>
</dict>
</array>
<key>PayloadDisplayName</key>
<string>EJBTest</string>
<key>PayloadIdentifier</key>
<string>bhaidass-macbook-pro.local.736DF58F-4375-420A-B9D6-7950684E0B3A</string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>A8F41F59-643C-44B5-9447-8AB88D6FCA49</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
变量中获得了生成的freemarker模板。
以下XML是更新文档属性后生成的文档的footer1.xml部分的内容,如下所述:footer1.xml after field updates
非常奇怪的事情(在我看来)是如果找不到某些属性,第5步抛出异常(ok),字段更新在错误的字段停止(ok)并且页眉和页脚中的所有字段都是正确的。在这种情况下,这是footer1.xml的内容。
在最后一种情况下,字段以不同的方式定义。我认为HTML转换器可以很好地处理最后一种情况,并在第一种情况下做错了。
我做错了什么或者我能做得更好?