0

I create a Java application to modify some SVG files. Here is my issue : I would like to add an elements to the DOM of my SVG files to create link on a rectangle. The SVG file is generated from another application. I need to do it in Java.

So here is what I did :

  • I used JASXP to try to parse and modify my SVG file.

I tried many configurations, using SAX, DOM API to parse it and here is the only which I success to create a document from my SVG file.

Here is my SVGFile :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
      'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg ... xmlns:xlink="http://www.w3.org/1999/xlink" ....xmlns="http://www.w3.org/2000/svg" ...>
<!--Generated by the Batik Graphics2D SVG Generator-->
<defs id="genericDefs"/>
<g>
  <defs id="defs1">
   ....define the clipath...
  </defs>

  HERE I WOULD LIKE TO INSERT OPEN A ELEMENT : <a ....>
  <g font-size="11" transform="translate(2,212)" fill-opacity="1"fill="rgb(192,255,255)" text-rendering="geometricPrecision" font-family="sans-serif" stroke="rgb(192,255,255)" font-weight="bold" stroke-opacity="1">
     <rect x="0" width="80" height="40" y="0" clip-path="url(#clipPath1)" stroke="none"/>
  </g>
  <g font-size="11" stroke-linecap="butt" transform="translate(2,212)" fill-opacity="1" fill="black" text-rendering="geometricPrecision" font-family="sans-serif" stroke-linejoin="round" stroke="black" font-weight="bold" stroke-opacity="1" stroke-miterlimit="0">
      <rect fill="none" x="0" width="80" height="40" y="0" clip-path="url(#clipPath1)"/>
 </g>
 <g font-size="11" transform="translate(2,212)" fill-opacity="1" fill="black" text-rendering="geometricPrecision" font-family="sans-serif" stroke="black" font-weight="bold" stroke-opacity="1">
      <text x="28" xml:space="preserve" y="12" clip-path="url(#clipPath4)"stroke="none" >Titre</text>
      <line y2="12" fill="none" x1="28" clip-path="url(#clipPath4)" x2="52" y1="12"/>       
 </g>
</g>
</svg>
 AND I WOULD LIKE TO CLOSE IT here : </a>

The code to obtain a DOM document from my SVG :

        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);

        File file = new File ("D:/mySVGFile.svg");
        String uri = file.toURI().toString();

        Document doc = f.createDocument(uri); 

To parse the document obtain I did that :

           Element racine = doc.getDocumentElement();
       String tag ="text";    // Because it's the only element I have store in an Array

    NodeList liste = doc.getElementsByTagName(tag);

        Element e = (Element) liste.item(0);    // element text = Titre
        Node target = e.getParentNode().getParentNode().getParentNode();
        Element link = doc.createElement("a"); 
        link.setAttribute("xlink:href", "DestinationFile.svg#67");
        target.insertBefore(link, target);

Here is the console error :

    org.w3c.dom.DOMException: The child node (type: 1, name: svg) is missing.
at org.apache.batik.dom.AbstractNode.createDOMException(AbstractNode.java:408)
at org.apache.batik.dom.AbstractParentNode.insertBefore(AbstractParentNode.java:78)
at SAXTagCount.main(SAXTagCount.java:60)

In fact I really don't know how can I create this element in Java for an SVG files.

Thanks by advance for your help !

Jim

2 Answers2

1

The line

Element link = doc.createElement("a");

is incorrect. To create an SVG <a> element, or indeed any svg element you must use createElementNS i.e.

Element link = doc.createElementNS("http://www.w3.org/2000/svg", "a");

One of your other problems is that you have too many getParentNode() calls. The parent of the text element is its enclosing <g>. Its parent is another <g> and its parent is the <svg> root element so your insertBefore is trying to insert the <a> before the <svg> root element and that's not allowed. Looks to me like you need to remove 2 getParentNode() calls to put it at the right level.

You've various other issues like inserting at the right place - somehow you need to find that <g> element and ideally it would have an id or some way to identify it otherwise you'd have to search for it. Also you'd need to collect all the elements you want to make into children of the <a>. You'd to that by reparenting each existing element using link.appendChild so that its a child of the <a> element. That's a lot to cover in one answer though.

target.insertBefore(link, target);

isn't valid either as you can't use target twice. The argument should be a child of target, not target itself.

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
0
/**
 * Use the SAXSVGDocumentFactory to parse the given URI into a DOM.
 * 
 * @param uri
 *            The path to the SVG file to read.
 * @return A Document instance that represents the SVG file.
 * @throws Exception
 *             The file could not be read.
 */
private Document createSVGDocument(String uri) throws IOException {

    String parser = XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
    return factory.createDocument(uri);
}
amoljdv06
  • 2,646
  • 1
  • 13
  • 18