Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a graph image (png, jpg ..) from an XML file with Java

I have an XML file and I want to create a graph based on some entities, then store this graph in an image, JPG or PNG.

So is there a library in Java to do something like this? Or are there some tricks by parsing XML files?

Here an example XML file:

<?xml version="1.0"?>
<process>
  <p n="1">Tove</p> 
  <p n="2">Jani</p> 
  <p n="2">Bill</p> 
  <p n="4">John</p> 
</process>

And the output will be like this:

enter image description here

like image 575
Ali Ben Messaoud Avatar asked Feb 05 '11 07:02

Ali Ben Messaoud


2 Answers

You can extract the names using one of the myriad of Java XML libraries. Here's an example using XPath from a Java DOM:

private static List<String> findNames(Document doc)
                                           throws XPathExpressionException {
  XPath xpath = XPathFactory.newInstance().newXPath();
  NodeList nodes = (NodeList) xpath.evaluate("/process/p", doc, 
                                                    XPathConstants.NODESET);
  List<String> names = new ArrayList<String>();
  for (int i = 0; i < nodes.getLength(); i++) {
    names.add(nodes.item(i).getTextContent());
  }
  return names;
}

Note: it may be a typo, but your XML is not well formed - attribute values must be quoted. XML parsing will fail otherwise.

some boxes

You can use the AWT API to draw whatever you want:

private static final int BORDER = 1;
private static final int PADDING = 2;
private static final int SPACER = 5;

private static void draw(Graphics2D g, List<String> names) {
  FontMetrics metrics = g.getFontMetrics();
  Rectangle box = new Rectangle(1, 1, 0, 0);
  box.height = metrics.getHeight() + (PADDING * 2);
  g.setColor(Color.WHITE);
  for (String name : names) {
    box.width = metrics.stringWidth(name) + (PADDING * 2);
    g.drawString(name, box.x + BORDER + PADDING, PADDING + BORDER +
                                                    metrics.getHeight());
    g.drawRect(box.x, box.y, box.width, box.height);
    box.x += box.width + (BORDER * 2) + SPACER;
  }
}

This code just draws the names with some boxes around them. I'm sure my offsets are all over the place, but you probably get the idea.

There is an imageio API that can save in a few popular data formats:

private static void save(List<String> names, File file) throws IOException {
  BufferedImage image = new BufferedImage(600, 50, BufferedImage.TYPE_INT_RGB);
  Graphics2D g = image.createGraphics();
  try {
    draw(g, names);
  } finally {
    g.dispose();
  }
  ImageIO.write(image, "png", file);
}
like image 169
McDowell Avatar answered Nov 13 '22 07:11

McDowell


I'd parse the XML and output a Graphviz DOT representation like this:

digraph {
  Tove -> Jani
  Jani -> Bill
  Bill -> John
}

Then I'd call the Graphviz dot executable from Java using ProcessRunner:

dot -Tpng -o file.png file.dot

See http://graphviz.org for further info.

like image 23
Fabian Steeg Avatar answered Nov 13 '22 06:11

Fabian Steeg