我正在使用 Flying Saucer 从 XHTML 转换为 PDF,它工作得很好,但现在我想添加书签,根据 fs 文档,它应该像这样完成:
<bookmarks>
<bookmark name='1. Foo bar baz' href='#1'>
<bookmark name='1.1 Baz quux' href='#1.2'>
</bookmark>
</bookmark>
<bookmark name='2. Foo bar baz' href='#2'>
<bookmark name='2.1 Baz quux' href='#2.2'>
</bookmark>
</bookmark>
</bookmarks>
那应该放在 HEAD 部分,我已经这样做了,但是 SAXParser 不会再读取文件,说:
line 11 column 14 - Error: <bookmarks> is not recognized!
line 11 column 25 - Error: <bookmark> is not recognized!
我设置了本地实体解析器,甚至将书签添加到 DTD,
<!--flying saucer bookmarks -->
<!ELEMENT bookmarks (#PCDATA)>
<!ATTLIST bookmarks %attrs;>
<!ELEMENT bookmark (#PCDATA)>
<!ATTLIST bookmark %attrs;>
但它就是不会解析,我没有想法,请帮忙。
编辑
我正在使用下面的代码来解析:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
builder.setEntityResolver(new LocalEntityResolver());
document = builder.parse(is);
编辑
这是 LocalEntityResolver:
class LocalEntityResolver implements EntityResolver {
private static final Logger LOG = ESAPI.getLogger(LocalEntityResolver.class);
private static final Map<String, String> DTDS;
static {
DTDS = new HashMap<String, String>();
DTDS.put("-//W3C//DTD XHTML 1.0 Strict//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
DTDS.put("-//W3C//DTD XHTML 1.0 Transitional//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd");
DTDS.put("-//W3C//ENTITIES Latin 1 for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent");
DTDS.put("-//W3C//ENTITIES Symbols for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent");
DTDS.put("-//W3C//ENTITIES Special for XHTML//EN",
"http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent");
}
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
InputSource input_source = null;
if (publicId != null && DTDS.containsKey(publicId)) {
LOG.debug(Logger.EVENT_SUCCESS, "Looking for local copy of [" + publicId + "]");
final String dtd_system_id = DTDS.get(publicId);
final String file_name = dtd_system_id.substring(
dtd_system_id.lastIndexOf('/') + 1, dtd_system_id.length());
InputStream input_stream = FileUtil.readStreamFromClasspath(
file_name, "my/class/path",
getClass().getClassLoader());
if (input_stream != null) {
LOG.debug(Logger.EVENT_SUCCESS, "Found local file [" + file_name + "]!");
input_source = new InputSource(input_stream);
}
}
return input_source;
}
}
我的文档生成器工厂实现是: com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
最佳答案
呃,终于找到问题了。很抱歉让你们调试代码,问题是在我的代码中,就在 DOM 解析发生之前调用了 JTidy.parse,这导致内容被解析为空,我什至没有注意到,实际错误是来自 SAX 的 文件过早结束
。
感谢 Matt Gibson,当我检查代码以编译一个简短的输入文档时,我发现了这个错误。
我的代码现在包括检查内容是否为空
/**
* parses String content into a valid XML document.
* @param content the content to be parsed.
* @return the parsed document or <tt>null</tt>
*/
private static Document parse(final String content) {
Document document = null;
try {
if (StringUtil.isNull(content)) {
throw new IllegalArgumentException("cannot parse null "
+ "content into a DOM object!");
}
InputStream is = new ByteArrayInputStream(content
.getBytes(CONTEXT.getEncoding()));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
builder.setEntityResolver(new LocalEntityResolver());
document = builder.parse(is);
} catch (Exception ex) {
LOG.error(Logger.EVENT_FAILURE, "parsing failed "
+ "for content[" + content + "]", ex);
}
return document;
}
关于java - 将 XHTML 和自定义标签读入 DOM 树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7121362/