1313 * See the License for the specific language governing permissions and
1414 * limitations under the License.
1515 */
16- package guru .nidi .graphviz .engine ;
16+ package guru .nidi .graphviz .model ;
1717
18- import guru .nidi .graphviz .model .Graph ;
19- import guru .nidi .graphviz .model .Link ;
2018import org .w3c .dom .Document ;
21- import org .w3c .dom .Node ;
19+ import org .w3c .dom .Element ;
2220import org .xml .sax .InputSource ;
2321import org .xml .sax .SAXException ;
2422
2523import javax .annotation .Nullable ;
24+ import javax .xml .XMLConstants ;
2625import javax .xml .namespace .QName ;
2726import javax .xml .parsers .*;
28- import javax .xml .transform .TransformerException ;
29- import javax .xml .transform .TransformerFactory ;
27+ import javax .xml .transform .*;
3028import javax .xml .transform .dom .DOMSource ;
3129import javax .xml .transform .stream .StreamResult ;
3230import javax .xml .xpath .*;
3331import java .io .*;
32+ import java .util .function .Consumer ;
3433
3534public class SvgElementFinder {
36- private static final DocumentBuilderFactory FACTORY = DocumentBuilderFactory . newInstance ();
37- private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory . newInstance ();
35+ private static final DocumentBuilderFactory FACTORY = builderFactory ();
36+ private static final TransformerFactory TRANSFORMER_FACTORY = transformerFactory ();
3837 private static final VariableResolver RESOLVER = new VariableResolver ();
3938 private static final XPath X_PATH = xPath (RESOLVER );
4039 private static final XPathExpression EXPR_G = pathExpression (X_PATH , "//g" );
4140 private static final XPathExpression EXPR_TITLE = pathExpression (X_PATH , "//title[text()=$var]" );
4241 private static final XPathExpression EXPR_TITLE_OR = pathExpression (X_PATH , "//title[text()=$var or text()=$alt]" );
4342 private final Document doc ;
4443
44+ public static String use (String svg , Consumer <SvgElementFinder > actions ) {
45+ final SvgElementFinder finder = new SvgElementFinder (svg );
46+ actions .accept (finder );
47+ return finder .getSvg ();
48+ }
49+
4550 public SvgElementFinder (String svg ) {
4651 try {
4752 doc = builder ().parse (new InputSource (new StringReader (svg )));
4853 } catch (SAXException | IOException e ) {
49- throw new GraphvizException ("Could not read SVG" , e );
54+ throw new AssertionError ("Could not read SVG" , e );
5055 }
5156 }
5257
@@ -60,58 +65,79 @@ public String getSvg() {
6065 }
6166 }
6267
63- public Node findGraph () {
64- return nodeExpr (EXPR_G , "" );
68+ public Element findGraph () {
69+ return ( Element ) nodeExpr (EXPR_G , "" );
6570 }
6671
6772 @ Nullable
68- public Node findNode (guru .nidi .graphviz .model .Node node ) {
73+ public Element findNode (guru .nidi .graphviz .model .Node node ) {
6974 return findNode (node .name ().toString ());
7075 }
7176
7277 @ Nullable
73- public Node findNode (String name ) {
74- final Node title = nodeExpr (EXPR_TITLE , name );
75- return title == null ? null : title .getParentNode ();
78+ public Element findNode (String name ) {
79+ final org . w3c . dom . Node title = nodeExpr (EXPR_TITLE , name );
80+ return title == null ? null : ( Element ) title .getParentNode ();
7681 }
7782
7883 @ Nullable
79- public Node findLink (Link link ) {
84+ public Element findLink (Link link ) {
8085 return findLink (link .from ().name ().toString (), link .to ().name ().toString ());
8186 }
8287
8388 @ Nullable
84- public Node findLink (String from , String to ) {
85- final Node title = nodeExpr (EXPR_TITLE_OR , from + "--" + to );
86- return title == null ? null : title .getParentNode ();
89+ public Element findLink (String from , String to ) {
90+ final org . w3c . dom . Node title = nodeExpr (EXPR_TITLE_OR , from + "--" + to );
91+ return title == null ? null : ( Element ) title .getParentNode ();
8792 }
8893
8994 @ Nullable
90- public Node findCluster (Graph cluster ) {
95+ public Element findCluster (Graph cluster ) {
9196 return findCluster (cluster .name ().toString ());
9297 }
9398
9499 @ Nullable
95- public Node findCluster (String name ) {
96- final Node title = nodeExpr (EXPR_TITLE , "cluster_" + name );
97- return title == null ? null : title .getParentNode ();
100+ public Element findCluster (String name ) {
101+ final org . w3c . dom . Node title = nodeExpr (EXPR_TITLE , "cluster_" + name );
102+ return title == null ? null : ( Element ) title .getParentNode ();
98103 }
99104
100105 @ Nullable
101- private Node nodeExpr (XPathExpression expr , String var ) {
106+ private org . w3c . dom . Node nodeExpr (XPathExpression expr , String var ) {
102107 RESOLVER .set (var );
103108 try {
104- return (Node ) expr .evaluate (doc , XPathConstants .NODE );
109+ return (org . w3c . dom . Node ) expr .evaluate (doc , XPathConstants .NODE );
105110 } catch (XPathExpressionException e ) {
106111 throw new AssertionError ("Could not execute XPath" , e );
107112 }
108113 }
109114
115+ private static DocumentBuilderFactory builderFactory () {
116+ try {
117+ final DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance ();
118+ factory .setFeature ("http://apache.org/xml/features/disallow-doctype-decl" , true );
119+ factory .setFeature (XMLConstants .FEATURE_SECURE_PROCESSING , true );
120+ return factory ;
121+ } catch (ParserConfigurationException e ) {
122+ throw new AssertionError ("Could not initialize DOM" , e );
123+ }
124+ }
125+
126+ private static TransformerFactory transformerFactory () {
127+ try {
128+ final TransformerFactory factory = TransformerFactory .newInstance ();
129+ factory .setFeature (XMLConstants .FEATURE_SECURE_PROCESSING , true );
130+ return factory ;
131+ } catch (TransformerConfigurationException e ) {
132+ throw new AssertionError ("Could not initialize DOM" , e );
133+ }
134+ }
135+
110136 private DocumentBuilder builder () {
111137 try {
112138 return FACTORY .newDocumentBuilder ();
113139 } catch (ParserConfigurationException e ) {
114- throw new RuntimeException ("Could not initialize DOM" , e );
140+ throw new AssertionError ("Could not initialize DOM" , e );
115141 }
116142 }
117143
@@ -130,15 +156,15 @@ private static XPathExpression pathExpression(XPath xPath, String exp) {
130156 }
131157
132158 private static class VariableResolver implements XPathVariableResolver {
133- private final static ThreadLocal <String > var = new ThreadLocal <>();
159+ private static final ThreadLocal <String > VAR = new ThreadLocal <>();
134160
135161 public void set (String value ) {
136- var .set (value );
162+ VAR .set (value );
137163 }
138164
139165 @ Override
140166 public Object resolveVariable (QName varName ) {
141- return varName .getLocalPart ().equals ("var" ) ? var .get () : var .get ().replace ("--" , "->" );
167+ return varName .getLocalPart ().equals ("var" ) ? VAR .get () : VAR .get ().replace ("--" , "->" );
142168 }
143169 }
144170}
0 commit comments