0

I am trying to read a largish (1 MB) svg file that is exported from an old program. I do not have access to this program or the data. I only have this exported svg file and I will probably have to import a freshly exported svg file somewhat regularly from this source. The first problem I find using batik is that it is very strict when reading this file. Firefox has no problem reading and displaying this file for example. Batik (including Squiggle can not display it because of some "custom" tags within the document). The exception I get is ...

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)

... So using the not entirely helpful link Writing a batik Dom Extension I managed to write the following ...

    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() );
}

But I get the same error, the System.out.println() statement is never hit so it is apparently not registering my factory correctly. On a side note is there anyway to make Batik less strict so that it just skips things it doesn't understand like Firefox does?

crowmagnumb
  • 5,059
  • 6
  • 28
  • 39

2 Answers2

1

Investigation indicates that the Batik 1.7.0 implementation doesn't allow you to create DOM extensions that intercept elements in the SVG namespace; it throws the exception at the point when it would otherwise drop through to the code that would do the lookup of the registered factory. I've no idea if this is intentional. What's interesting is that there doesn't seem to be a <menu> element defined in current versions of the SVG specification at all; it's either been long deprecated or was an extension that's been placed in the wrong namespace. Ugh.

The easiest workaround might be to use an XSLT stylesheet to remap the <menu> element into another namespace — that's a pretty trivial stylesheet IIRC — and then to register your custom handler to deal with that as you choose (if it is even necessary).

Donal Fellows
  • 120,022
  • 18
  • 134
  • 199
1

That's a fine solution for now as I can just run the file through this filter. In the nearish future, I will want to be able to have users upload svg files themselves and then it will need to be a little more robust of a solution. Here is the xslt I created ...

<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>

... and I ran ...

java -jar /usr/share/java/saxon.jar original.svg svgfix.xslt > fixed.svg
crowmagnumb
  • 5,059
  • 6
  • 28
  • 39
  • Sorry, I couldn't figure out how to expand on your answer with code bits unless I made it an answer of my own. – crowmagnumb Nov 21 '12 at 01:53
  • That's OK. I'm happy that we've managed to find a way around it (without delving into the code that produced what appears to be a buggy SVG file, which was my first inclination). – Donal Fellows Nov 21 '12 at 09:00