我正在尝试使用Java将XML转换为SVG,但看起来形状信息在此过程中丢失了。
给出一个简单的draw.io
图表:
运行XmlToSvg.java后,我得到:
我将其保存为未压缩的XML。我正在使用mxGraph Repo
中的mxgraph-all.jar
您知道是否有隐藏设置可以保留形状和颜色吗?
答案 0 :(得分:3)
简短版
看起来尽管在GitHub页面上有声明,但除了JavaScript之外没有任何实现真正功能齐全且生产就绪。特别是Java实现(以及.Net和PHP服务器端实现)并不支持" Cube"开箱即用。
更多详情
<强> 颜色 强>
您没有提供您的示例XML,但是当我生成类似的图表时,我会得到类似
的内容<?xml version="1.0" encoding="UTF-8"?>
<mxGraphModel dx="1426" dy="816" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850"
pageHeight="1100" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="445" y="60" width="230" height="150" as="geometry"/>
</mxCell>
<mxCell id="3" value="" style="ellipse;shape=doubleEllipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="1" vertex="1">
<mxGeometry x="500" y="320" width="120" height="120" as="geometry"/>
</mxCell>
<mxCell id="4" value="" style="endArrow=classic;html=1;" parent="1" source="3" target="2" edge="1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="430" y="510" as="sourcePoint"/>
<mxPoint x="480" y="460" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="5" value="" style="shape=cube;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="80" y="320" width="170" height="110" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
重要的是,此XML不包含任何有关颜色的信息。因此关于&#34;保留颜色的整体想法&#34;是错的。在Java实现中,您可以配置&#34;默认颜色&#34;使用mxStylesheet
类的实例并将其用于初始化mxGraph
对象。例如,要将颜色更改为黑白,您可以执行以下操作:
mxStylesheet stylesheet = new mxStylesheet();
// configure "figures" aka "vertex"
{
Map<String, Object> style = stylesheet.getDefaultVertexStyle();
style.put(mxConstants.STYLE_FILLCOLOR, "#FFFFFF");
style.put(mxConstants.STYLE_STROKECOLOR, "#000000");
style.put(mxConstants.STYLE_FONTCOLOR, "#000000");
}
// configure "lines" aka "edges"
{
Map<String, Object> style = stylesheet.getDefaultEdgeStyle();
style.put(mxConstants.STYLE_STROKECOLOR, "#000000");
style.put(mxConstants.STYLE_FONTCOLOR, "#000000");
}
mxGraph graph = new mxGraph(stylesheet);
您可以查看mxStylesheet.createDefaultVertexStyle和mxStylesheet.createDefaultEdgeStyle了解详细信息。
<强> 形状 强>
&#34; 椭圆&#34;形状处理不正确,因为没有代码可以解析"ellipse;whiteSpace=wrap;html=1;"
并且理解形状应该是&#34;椭圆&#34; (将此字母指向&#34;双椭圆&#34;样式"ellipse;shape=doubleEllipse;whiteSpace=wrap;html=1;aspect=fixed;"
,其中包含显式shape
值。在JS实现中,样式的第一部分似乎选择了一个处理函数,它将处理字符串的其余部分并进行实际工作。在Java implmenetation中似乎没有这样的功能。您可以使用&#34;命名样式&#34;来解决这个问题。功能和定义相应的&#34;处理程序的默认形状&#34;在像这样的mxStylesheet
对象中:
// I just copied the whole list of mxConstants.SHAPE_ here
// you probably should filter it by removing non-primitive shapes
// such as mxConstants.SHAPE_DOUBLE_ELLIPSE
String[] shapes = new String[] {
mxConstants.SHAPE_RECTANGLE,
mxConstants.SHAPE_ELLIPSE,
mxConstants.SHAPE_DOUBLE_RECTANGLE,
mxConstants.SHAPE_DOUBLE_ELLIPSE,
mxConstants.SHAPE_RHOMBUS,
mxConstants.SHAPE_LINE,
mxConstants.SHAPE_IMAGE,
mxConstants.SHAPE_ARROW,
mxConstants.SHAPE_CURVE,
mxConstants.SHAPE_LABEL,
mxConstants.SHAPE_CYLINDER,
mxConstants.SHAPE_SWIMLANE,
mxConstants.SHAPE_CONNECTOR,
mxConstants.SHAPE_ACTOR,
mxConstants.SHAPE_CLOUD,
mxConstants.SHAPE_TRIANGLE,
mxConstants.SHAPE_HEXAGON,
};
Map<String, Map<String, Object>> styles = stylesheet.getStyles();
for (String sh : shapes)
{
Map<String, Object> style = new HashMap<>();
style.put(mxConstants.STYLE_SHAPE, sh);
styles.put(sh, style);
}
您仍然可能会注意到mxConstants.SHAPE_
的列表并不包含&#34; 多维数据集 &#34;。在JS实现&#34; cube&#34;是一个复合形状,由examples/grapheditor/www/js/Shape.js中的专用处理程序处理,它不是核心库的一部分!这意味着如果你想在Java代码中支持这种高级形状,你必须自己推出代码来自己处理它。
P.S。通过所有这些更改(黑客),我在第一个代码段中使用来自XML的Java代码获得的图像是:
答案 1 :(得分:0)
有一个XML文件,其中包含最通用形状的参数。您应该将其加载到样式表中,以使图像看起来与在编辑器中绘制的图像完全一样。默认样式表为default.xml。
因此,首先让您的代码获得两件事:样式表和图表内容。
mxStylesheet stylesheet = new mxStylesheet(); // mxgraph-core.jar
InputSource is = new InputSource(new StringReader(stylesheetText));
Document document = documentBuilder.parse(is);
mxCodec codec = new mxCodec(document);
codec.decode(document.getDocumentElement(), stylesheet);
mxIGraphModel model = new mxGraphModel();
mxGraph graph = new mxGraph(model, context.stylesheet);
is = new InputSource(new StringReader(diagramText));
document = documentBuilder.parse(new InputSource(is));
codec = new mxCodec(document);
codec.decode(document.getDocumentElement(), model);
final Document svgDocument = documentBuilder.newDocument();
mxCellRenderer.drawCells(
graph,
null,
1d,
null,
new mxCellRenderer.CanvasFactory() {
@Override
public mxICanvas createCanvas(int width, int height) {
Element root = output.createElement("svg");
String w = Integer.toString(width);
String h = Integer.toString(height);
root.setAttribute("width", w);
root.setAttribute("height", h);
root.setAttribute("viewBox", "0 0 " + w + " " + h);
root.setAttribute("version", "1.1");
root.setAttribute("xmlns", "http://www.w3.org/2000/svg");
root.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
output.appendChild(root);
mxSvgCanvas canvas = new mxSvgCanvas(svgDocument);
canvas.setEmbedded(true);
return canvas;
}
});
return svgDocument; // this is the result
接下来,创建SVG图像的最简单方法是利用mxgraph-core.jar中的类。看起来像这样
function convertToSVG(diagramText, stylesheetText) {
var stylesheet = new mxStylesheet();
var doc = mxUtils.parseXml(stylesheetText);
var stylesheetRoot = doc.documentElement;
var stylesheetCodec = new mxCodec(doc);
var dom = document.implementation;
stylesheetCodec.decode(stylesheetRoot, stylesheet);
doc = dom.createDocument(null, "div", null);
var model = new mxGraphModel();
var graph = new mxGraph(doc.documentElement, model, "exact", stylesheet);
doc = new DOMParser().parseFromString(diagram, "text/xml");
var codec = new mxCodec(doc);
codec.decode(doc.documentElement, model);
doc = dom.createDocument("http://www.w3.org/2000/svg", "svg", null);
var svgRoot = doc.documentElement;
var bounds = graph.getGraphBounds();
svgRoot.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgRoot.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
svgRoot.setAttribute("width", bounds.width);
svgRoot.setAttribute("height", bounds.height);
svgRoot.setAttribute("viewBox", "0 0 " + bounds.width + " " + bounds.height);
svgRoot.setAttribute("version", "1.1");
var svgCanvas = new mxSvgCanvas2D(svgRoot);
svgCanvas.translate(-bounds.x, -bounds.y);
var exporter = new mxImageExport();
var state = graph.getView().getState(model.root);
exporter.drawState(state, svgCanvas);
var result = new XMLSerializer().serializeToString(doc);
return result;
}
但是,正如SergGr所指出的,mxgraph库的Java实现不包含一些有用的形状。它们的绘制规则由Shape.js中的JavaScript函数描述。
我试图在Java标准库附带的ScriptEngine中执行JavaScript。不幸的是,这个想法没有用,因为内部深处的JavaScript代码与浏览器交互。
但是,如果我们在浏览器中运行代码,则效果很好。我用HtmlUnit成功做到了。
编写一个JavaScript函数以从Java调用:
String jsFunction = getAsString("convertToSVG.js");
Path file = Files.createTempFile("44179673-", ".html"); // do not forget to delete it
String hmltText = "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head><title>Empty file</title></head><body/></html>";
Files.write(file, Arrays.asList(htmlText));
WebClient webClient = new WebClient(); // net.sourceforge.htmlunit:htmlunit
HtmlPage page = webClient.getPage(file.toUri().toString());
String initScript = ""
+ "var mxLoadResources = false;"
+ "var mxLoadStylesheets = false;"
+ "var urlParams = new Object();";
page.executeJavaScript(initScript);
page.executeJavaScript(getAsString("mxClient.min.js"));
page.executeJavaScript(getAsString("Graph.js")); // Shape.js depends on it
page.executeJavaScript(getAsString("Shapes.js"));
ScriptResult scriptResult = page.executeJavaScript(jsFunction);
Object convertFunc = scriptResult.getJavaScriptResult();
Object args[] = new Object[]{ diagramText, stylesheetText };
scriptResult = page.executeJavaScriptFunction(convertFunc, null, args, null);
String svg = scriptResult.getJavaScriptResult().toString();
将此文本加载到String中并运行以下代码
<Directory Id="VS2017_IDE_DIR">
<Directory Id="VS2017_EXTENSIONS_DIR">
<Directory Id="VS2017_MYCOMPANY_EX" Name="MYCOMPANY">
<Directory Id="VS2017_AUTORUNNER_EX" Name="MYCOMPANY Extension">
<Directory Id="VS2017_AUTORUNNER_EX_VERSION" Name="$(var.MajorAndMinorVersion)">
<Component Id="VS2017_AUTORUNNER_EXTENSIONSHORTCUTS" Guid="">
<Condition>VS2017DEVENV</Condition>
<CreateFolder />
<util:RestartResource Path="[VS2017DEVENV]"/>
<RemoveFolder Id="REMOVE_VS_VERSION_VS2017" On="uninstall" Directory="VS2017_MYCOMPANY_EX" />
<RemoveFolder Id="REMOVE_VS2017_EXTENSIONS" On="uninstall" Directory="VS2017_AUTORUNNER_EX" />
<RemoveFolder Id="REMOVE_VS2017_MYCOMPANY_EX" On="uninstall" Directory="VS2017_AUTORUNNER_EX_VERSION" />
<File Source="$(var.ManagedBinariesDir)VisualStudioExtension\extension.vsixmanifest" Name="extension.vsixmanifest"
Id="extension.vsixmanifest_VS2017" />
<File Source="$(var.ManagedBinariesDir)VisualStudioExtension\MYCOMPANY.VSExtension.pkgdef"
Name="MYCOMPANY.VSExtension.pkgdef" Id="MYCOMPANY.AutoRunner.pkgdef_VS2017" />
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
上面的代码对我来说似乎很好。