XSL-FO:“无法为嵌入式svg

时间:2017-03-06 23:32:15

标签: svg xslt-1.0 xsl-fo apache-fop

我正在使用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]       在......

2 个答案:

答案 0 :(得分:0)

尝试在xml:base元素中添加<svg>属性。

xml:basehttps://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")