【问题标题】:Using Custom Element Factory When Reading SVG File Using Batik使用 Batik 读取 SVG 文件时使用自定义元素工厂
【发布时间】:2012-12-06 02:30:27
【问题描述】:

我正在尝试读取从旧程序导出的较大 (1 MB) svg 文件。我无权访问该程序或数据。我只有这个导出的 svg 文件,我可能需要定期从这个源导入一个新导出的 svg 文件。我发现使用蜡染的第一个问题是阅读此文件时非常严格。例如,Firefox 读取和显示此文件没有问题。蜡染(包括 Squiggle 无法显示,因为文档中有一些“自定义”标签)。我得到的例外是......

org.w3c.dom.DOMException: The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: menu).
    at org.apache.batik.dom.AbstractNode.createDOMException(AbstractNode.java:408)
    at org.apache.batik.dom.svg.SVGDOMImplementation.createElementNS(SVGDOMImplementation.java:211)
    at org.apache.batik.dom.svg.SVGOMDocument.createElementNS(SVGOMDocument.java:372)
    at org.apache.batik.dom.util.SAXDocumentFactory.startElement(SAXDocumentFactory.java:625)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:501)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:400)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2756)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:647)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:140)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:511)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:808)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
    at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:431)
    at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:349)
    at org.apache.batik.dom.svg.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:200)
    at com.samsix.nrg.io.SvgFileImporter.importFile(SvgFileImporter.java:74)

...所以使用不完全有用的链接Writing a batik Dom Extension 我设法写了以下...

    public ImportReport importFile( final String    uri )
    throws
        IOException
{
    String parser = XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);

    SVGDOMImplementation    implementation = (SVGDOMImplementation) factory.getDOMImplementation( null );

    implementation.registerCustomElementFactory( "http://www.w3.org/2000/svg",
                                                 "menu",
                                                 new ExtensibleDOMImplementation.ElementFactory() {
                                                    @Override
                                                    public Element create( final String prefix,
                                                                           final Document doc )
                                                    {
                                                        System.out.println( "Element.create: " + prefix );
                                                        return new GenericElement( "prefix",
                                                                                   (org.apache.batik.dom.AbstractDocument) doc );
                                                    }
                                                } );

    SVGDocument    doc = (SVGDocument) factory.createDocument( uri );

    System.out.println( doc.getDocumentURI() );
}

但是我得到了同样的错误, System.out.println() 语句从未被命中,所以它显然没有正确注册我的工厂。附带说明一下,无论如何,Batik 是否不那么严格,以便它像 Firefox 那样跳过它不理解的东西?

【问题讨论】:

  • 现在很好奇;我找不到当前 SVG 规范中定义的 menu 元素……

标签: java svg batik


【解决方案1】:

调查表明Batik 1.7.0 implementation 不允许您创建拦截 SVG 命名空间中元素的 DOM 扩展;它会在其他情况下抛出异常,否则它会直接进入将执行注册工厂查找的代码。我不知道这是不是故意的。 有趣的是,在当前版本的SVG specification 中似乎根本没有定义<menu> 元素。它要么已被弃用很久,要么是放置在错误命名空间中的扩展。呃。

最简单的解决方法可能是使用 XSLT 样式表将 <menu> 元素重新映射到另一个命名空间 - 这是一个非常简单的样式表 IIRC - 然后注册您的自定义处理程序以根据您的选择进行处理(如果它甚至必要)。

【讨论】:

    【解决方案2】:

    目前这是一个很好的解决方案,因为我可以通过这个过滤器运行文件。在不久的将来,我希望能够让用户自己上传 svg 文件,然后它需要一个更强大的解决方案。这是我创建的 xslt ...

    <xsl:stylesheet version="1.0" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <!--Identity Transform.-->
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="svg:menu"/>
    </xsl:stylesheet>
    

    ...我跑了...

    java -jar /usr/share/java/saxon.jar original.svg svgfix.xslt > fixed.svg
    

    【讨论】:

    • 抱歉,我无法弄清楚如何用代码位扩展您的答案,除非我自己做出了答案。
    • 没关系。我很高兴我们设法找到了解决方法(没有深入研究产生似乎有问题的 SVG 文件的代码,这是我的第一个倾向)。
    猜你喜欢
    • 2014-11-24
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-02
    相关资源
    最近更新 更多