我正在使用Apache FOP 2.1,JAXB和XSLT 1.0生成PDF。该模板有一些嵌入式SVG。 PDF呈现没有任何问题,但是FO会抛出使我的日志混乱的错误。
设定:
XslProcessor.java
public XslProcessor(File f) {
try {
URIResolverAdapter uriResolverAdapter = new URIResolverAdapter(new UserAgentUriResolver());
FopFactoryBuilder builder = new FopFactoryBuilder(URI.create("/"), uriResolverAdapter);
DefaultConfigurationBuilder defaultConfigurationBuilder = new DefaultConfigurationBuilder();
builder.setConfiguration(defaultConfigurationBuilder.buildFromFile("config/pdf/fop.xconf"));
fopFactory = builder.build();
transformerFactory = TransformerFactory.newInstance();
transformFile = f;
} catch (IOException | SAXException | ConfigurationException e) {
throw new RuntimeException(e);
}
}
public synchronized void process(InputStream is, OutputStream os) {
try {
try(BufferedOutputStream bufferedOut = new BufferedOutputStream(os)) {
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, bufferedOut);
Source xslt = new StreamSource(transformFile);
Transformer transformer = transformerFactory.newTransformer(xslt);
Source source = new StreamSource(is);
Result result = new SAXResult(fop.getDefaultHandler());
transformer.transform(source, result);
}
os.flush();
os.close();
} catch (IOException | FOPException | TransformerException e) {
throw new RuntimeException(e);
}
}
UserAgentUriResolver.java
public class UserAgentUriResolver implements URIResolver {
private static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36";
private static final String REFERRER = "https://www.google.com";
@Override
public Source resolve(String href, String base) throws TransformerException {
try {
URL url = new URL(href);
URLConnection connection = url.openConnection();
connection.setRequestProperty("User-Agent", USER_AGENT);
connection.setRequestProperty("Referrer", REFERRER);
return new StreamSource(connection.getInputStream());
} catch (IOException e) {
return new StreamSource(new ByteArrayInputStream(new byte[0]));
}
}
}
示例模板:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="29.7cm"
page-width="21cm">
<fo:region-body/>
<fo:region-after extent="1.25cm"/>
</fo:simple-page-master>
<fo:page-sequence-master master-name="all">
<fo:repeatable-page-master-alternatives>
<fo:conditional-page-master-reference master-reference="page"/>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="all">
<fo:static-content flow-name="xsl-region-after">
<fo:block>
<fo:instream-foreign-object>
<!-- SVG here! -->
<svg xmlns="http://www.w3.org/2000/svg" xml:base="http://www.example.com/">
<rect height="20" width="100%" fill="#ababab"></rect>
</svg>
</fo:instream-foreign-object>
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<fo:block>
<xsl:apply-templates/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
对于模板中的每个svg,我得到
org.apache.fop.fo.FONode:无法为svg设置基本网址
java.lang.IllegalArgumentException:URI不是绝对的 在java.net.URI.toURL(URI.java:1088)〜[na:1.8.0_91] 在org.apache.fop.fo.extensions.svg.SVGElement.getDimension(SVGElement.java:77)〜[fop-2.1.jar:na] at org.apache.fop.fo.flow.InstreamForeignObject.prepareIntrinsicSize(InstreamForeignObject.java:112)[fop-2.1.jar:na] at org.apache.fop.fo.flow.InstreamForeignObject.getIntrinsicWidth(InstreamForeignObject.java:125)[fop-2.1.jar:na] 在org.apache.fop.layoutmgr.inline.AbstractGraphicsLayoutManager.getInlineArea(AbstractGraphicsLayoutManager.java:60)[fop-2.1.jar:na] 在......
答案 0 :(得分:0)
尝试在xml:base
元素中添加<svg>
属性。
xml:base
(https://www.w3.org/TR/xmlbase/)比XSL 1.1建议书更新。这应该没关系,因为无论如何你都要将它添加到非XSL <svg>
元素,并且xml:base
在SVG 1.1中:https://www.w3.org/TR/SVG/struct.html#Core.attrib
为什么FOP不使用FO文档的base-uri作为SVG的base-uri是个谜,所以这可能会也可能不会。
答案 1 :(得分:0)
省略或更改default base URI for resolving resource URIs
应该会有所帮助。(请参阅EnvironmentProfile)如果设置了基本URI,则需要absolute
URI,例如:file:///
。
绝对 URI指定方案;一个非绝对的URI被认为是 relative 。 URI也根据它们是不透明还是分层进行分类。 java.net. URI
您可以通过编程方式设置此URI。在我的代码中,它看起来像这样:
new FopFactoryBuilder(URI.create("file:///"), uriResolverAdapter);
<强>背景强>
在类org.apache.fop.fo.extensions.svg.SVGElement
中,基础java.net.URI转换为URL
URI baseUri = getUserAgent().getResourceResolver().getBaseURI();
if (baseUri != null) {
SVGOMDocument svgdoc = (SVGOMDocument)doc;
svgdoc.setURLObject(baseUri.toURL());
}
方法URI :: toURL正在检查方案。如果错过了该方案,则会抛出IllegalArgumentException("URI is not absolute")
。