3

Is there a way for me to render and parse the SVG element from a html page rendered by javascript in Java, for example: http://bl.ocks.org/mbostock/raw/4063269/, which in the case is using d3.js.

kaqqao
  • 10,809
  • 4
  • 50
  • 101
David Zhao
  • 3,726
  • 11
  • 42
  • 58
  • Just to add, I've tried HtmlUnit, jsoup, and even investigated in SWT, but to no avail. That's why the question is kinda broad, as I don't want to limit the solution to one tool. – David Zhao Nov 03 '16 at 15:47
  • Possible duplicate of http://stackoverflow.com/questions/26027313/how-to-load-and-parse-svg-documents? – define cindy const Nov 07 '16 at 16:59
  • @definecindyconst This is not the duplicate of [http://stackoverflow.com/questions/26027313/how-to-load-and-parse-svg-documents], parsing SVG is easy. – David Zhao Nov 07 '16 at 17:00
  • 1
    I'm not sure what you're expecting here, this question is quite unclear. You will need something to render the SVG (you say JavaScript, so are you expecting to have a full JS VM?) and to display it. How do you want it to be displayed? Swing or JavaFX? Can you simply use a [WebView](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/web/WebView.html)? – Whymarrh Nov 07 '16 at 17:01
  • Can you elaborate your question with some example? – mayank agrawal Nov 08 '16 at 09:23
  • @mayankagrawal The question is quite simple and straightforward: retrieve (or parse) the SVG element generated by the javascript in the example web page. – David Zhao Nov 08 '16 at 16:52
  • Retrieve in what sense? As a `String`? Render it on screen in a desktop app? These are all very different cases. You need to be more precise. – kaqqao Nov 10 '16 at 15:26
  • https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility – Sanka Nov 14 '16 at 16:54

2 Answers2

2

If I understood you question correctly, your problem is that tools you used (HtmlUnit) cannot handle complex JS (d3.js).

In this case there is nothing better than using an actual browser. You can use Selenium to open your page with a remote controlled browser instance and get JS rendered html from there.

This tutorial contains pretty much all you need. Except the getting html part, you can find it in this SO answer.

After that you can feed the html to any parser you want.

EDIT

Just thought of another way, you can try WebKit Html2Pdf. Its purpose is to create PDF files but it uses WebKit under the hood and you can inject custom script (like document.onload callback) that will post SVG contents to you service after page is loaded.

But I wouldnt go that road, it has many limitations (basically only works for direct urls) and overall is pretty messed up.

Community
  • 1
  • 1
chimmi
  • 1,942
  • 14
  • 29
  • you did understand the question correctly, htmlunit itself doesn't have a javascript engine. However, I'd like to have a "pure" java way, wonder if Rhino or Nashborn can handle this. – David Zhao Nov 08 '16 at 16:57
  • In this case you should present your actual case, because there is quite a few options and, as to my knowledge, none of them are ideal, so no one can tell you with certainty that they will work for you. – chimmi Nov 08 '16 at 17:29
1

If what you're trying to do is get the SVG content as a String, Selenium is your best choice, like @chimmi said. But, you might get away without a real browser window opening by using PhantomJS instead.

In theory, it should work like this:

System.setProperty("phantomjs.binary.path", "/path/to/phantomjs");
WebDriver driver = new PhantomJSDriver();
// Open your page with SVG
driver.get("http://localhost:8080/svgpage");

// Find the SVG
WebElement svg = driver.findElement(By.tageName("svg"));
// Get its XML content
String xml = svg.getAttribute("outerHTML");

From here, you could use Batik if you want to actually render the SVG on screen in your non-web app.

Or, if all you wanted was to make assertions on the SVG contents for testing purposes, remember you can select sub-elements using normal CSS or XPath selectors:

//Select all <path> elements within the SVG
Lis<WebElement> pathElementsInSVG = svg.findElements(By.tagName("path"));
//Assert there is 4 <path>s 
assert pathElementsInSVG.size() == 4
kaqqao
  • 10,809
  • 4
  • 50
  • 101