fix(测试跟踪): 导入xmind支持 自由主题风格/支持多画布

This commit is contained in:
fit2-zhao 2020-09-30 11:14:01 +08:00
parent 1c7ce5e20b
commit 8ba24261b6
4 changed files with 188 additions and 157 deletions

View File

@ -270,25 +270,34 @@ public class XmindCaseParser {
StringBuffer processBuffer = new StringBuffer(); StringBuffer processBuffer = new StringBuffer();
try { try {
// 获取思维导图内容 // 获取思维导图内容
JsonRootBean root = XmindParser.parseObject(multipartFile); List<JsonRootBean> roots = XmindParser.parseObject(multipartFile);
if (root != null && root.getRootTopic() != null && root.getRootTopic().getChildren() != null) { for (JsonRootBean root : roots) {
// 判断是模块还是用例 if (root != null && root.getRootTopic() != null && root.getRootTopic().getChildren() != null) {
for (Attached item : root.getRootTopic().getChildren().getAttached()) { // 判断是模块还是用例
if (isAvailable(item.getTitle(), "(?:tc:|tc|tc)")) { // 用例 for (Attached item : root.getRootTopic().getChildren().getAttached()) {
return replace(item.getTitle(), "(?:tc:|tc|tc)") + "" + Translator.get("test_case_create_module_fail"); if (isAvailable(item.getTitle(), "(?:tc:|tc|tc)")) { // 用例
} else { return replace(item.getTitle(), "(?:tc:|tc|tc)") + "" + Translator.get("test_case_create_module_fail");
item.setPath(item.getTitle()); } else {
if (item.getChildren() != null && !item.getChildren().getAttached().isEmpty()) { String nodePath = item.getTitle();
recursion(processBuffer, item, 1, item.getChildren().getAttached()); item.setPath(nodePath);
if (item.getChildren() != null && !item.getChildren().getAttached().isEmpty()) {
recursion(processBuffer, item, 1, item.getChildren().getAttached());
} else {
if (!nodePath.startsWith("/")) {
nodePath = "/" + nodePath;
}
if (nodePath.endsWith("/")) {
nodePath = nodePath.substring(0, nodePath.length() - 1);
}
nodePaths.add(nodePath); // 没有用例的路径
}
} }
} }
} }
} }
this.validate(); this.validate();
} catch (Exception ex) { } catch (Exception ex) {
processBuffer.append(Translator.get("incorrect_format")); return ex.getMessage();
LogUtil.error(ex.getMessage());
return "xmind "+Translator.get("incorrect_format");
} }
return process.toString(); return process.toString();
} }

View File

@ -5,75 +5,83 @@ import org.json.JSONObject;
import org.json.XML; import org.json.XML;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class XmindLegacy { public class XmindLegacy {
/** /**
* 返回content.xml和comments.xml合并后的json * 返回content.xml和comments.xml合并后的json
* *
* @param xmlContent * @param xmlContent
* @param xmlComments * @param xmlComments
* @return * @return
* @throws IOException * @throws IOException
* @throws DocumentException * @throws DocumentException
*/ */
public static String getContent(String xmlContent, String xmlComments) throws IOException, DocumentException { public static List<String> getContent(String xmlContent, String xmlComments) throws IOException, DocumentException {
// 删除content.xml里面不能识别的字符串 // 删除content.xml里面不能识别的字符串
xmlContent = xmlContent.replace("xmlns=\"urn:xmind:xmap:xmlns:content:2.0\"", ""); xmlContent = xmlContent.replace("xmlns=\"urn:xmind:xmap:xmlns:content:2.0\"", "");
xmlContent = xmlContent.replace("xmlns:fo=\"http://www.w3.org/1999/XSL/Format\"", ""); xmlContent = xmlContent.replace("xmlns:fo=\"http://www.w3.org/1999/XSL/Format\"", "");
// 删除<topic>节点 // 删除<topic>节点
xmlContent = xmlContent.replace("<topics type=\"attached\">", ""); xmlContent = xmlContent.replace("<topics type=\"attached\">", "");
xmlContent = xmlContent.replace("</topics>", ""); xmlContent = xmlContent.replace("</topics>", "");
// 去除title中svg:width属性 // 去除title中svg:width属性
xmlContent = xmlContent.replaceAll("<title svg:width=\"[0-9]*\">", "<title>"); xmlContent = xmlContent.replaceAll("<title svg:width=\"[0-9]*\">", "<title>");
//去除自由风格主题
xmlContent = xmlContent.replaceAll("<topics type=\"detached\">", "");
Document document = DocumentHelper.parseText(xmlContent);// 读取XML文件,获得document对象 Document document = DocumentHelper.parseText(xmlContent);// 读取XML文件,获得document对象
Element root = document.getRootElement(); Element root = document.getRootElement();
List<Node> topics = root.selectNodes("//topic"); List<Node> topics = root.selectNodes("//topic");
if (xmlComments != null) { if (xmlComments != null) {
// 删除comments.xml里面不能识别的字符串 // 删除comments.xml里面不能识别的字符串
xmlComments = xmlComments.replace("xmlns=\"urn:xmind:xmap:xmlns:comments:2.0\"", ""); xmlComments = xmlComments.replace("xmlns=\"urn:xmind:xmap:xmlns:comments:2.0\"", "");
// 添加评论到content中 // 添加评论到content中
Document commentDocument = DocumentHelper.parseText(xmlComments); Document commentDocument = DocumentHelper.parseText(xmlComments);
List<Node> commentsList = commentDocument.selectNodes("//comment"); List<Node> commentsList = commentDocument.selectNodes("//comment");
for (Node topic : topics) { for (Node topic : topics) {
for (Node commentNode : commentsList) { for (Node commentNode : commentsList) {
Element commentElement = (Element) commentNode; Element commentElement = (Element) commentNode;
Element topicElement = (Element) topic; Element topicElement = (Element) topic;
if (topicElement.attribute("id").getValue() if (topicElement.attribute("id").getValue()
.equals(commentElement.attribute("object-id").getValue())) { .equals(commentElement.attribute("object-id").getValue())) {
Element comment = topicElement.addElement("comments"); Element comment = topicElement.addElement("comments");
comment.addAttribute("creationTime", commentElement.attribute("time").getValue()); comment.addAttribute("creationTime", commentElement.attribute("time").getValue());
comment.addAttribute("author", commentElement.attribute("author").getValue()); comment.addAttribute("author", commentElement.attribute("author").getValue());
comment.addAttribute("content", commentElement.element("content").getText()); comment.addAttribute("content", commentElement.element("content").getText());
} }
} }
} }
} }
// 第一个topic转换为json中的rootTopic // 第一个topic转换为json中的rootTopic
Node rootTopic = root.selectSingleNode("/xmap-content/sheet/topic"); List<Node> rootTopics = root.selectNodes("/xmap-content/sheet/topic");
rootTopic.setName("rootTopic"); for (Node rootTopic : rootTopics) {
rootTopic.setName("rootTopic");
// 将xml中topic节点转换为attached节点 // 将xml中topic节点转换为attached节点
List<Node> topicList = rootTopic.selectNodes("//topic"); List<Node> topicList = rootTopic.selectNodes("//topic");
for (Node node : topicList) {
node.setName("attached");
}
for (Node node : topicList) { }
node.setName("attached");
} List<String> sheets = new ArrayList<>();
// 选取第一个sheet for (Element sheet : root.elements("sheet")) {
Element sheet = root.elements("sheet").get(0); String res = sheet.asXML();
String res = sheet.asXML(); // 将xml转为json
// 将xml转为json JSONObject xmlJSONObj = XML.toJSONObject(res);
JSONObject xmlJSONObj = XML.toJSONObject(res); JSONObject jsonObject = xmlJSONObj.getJSONObject("sheet");
JSONObject jsonObject = xmlJSONObj.getJSONObject("sheet"); sheets.add(jsonObject.toString(4));
// 设置缩进 }
return jsonObject.toString(4); // 设置缩进
} return sheets;
}
} }

View File

@ -34,61 +34,68 @@ public class XmindParser {
* @throws ArchiveException * @throws ArchiveException
* @throws DocumentException * @throws DocumentException
*/ */
public static String parseJson(MultipartFile multipartFile) throws IOException, ArchiveException, DocumentException { public static List<String> parseJson(MultipartFile multipartFile) throws IOException, ArchiveException, DocumentException {
File file = FileUtil.multipartFileToFile(multipartFile); File file = FileUtil.multipartFileToFile(multipartFile);
List<String> contents = null;
String res = null;
if (file == null || !file.exists()) if (file == null || !file.exists())
MSException.throwException(Translator.get("incorrect_format")); MSException.throwException(Translator.get("incorrect_format"));
try {
String res = ZipUtils.extract(file); res = ZipUtils.extract(file);
String content = null; if (isXmindZen(res, file)) {
if (isXmindZen(res, file)) { contents = (getXmindZenContent(file, res));
content = getXmindZenContent(file, res); } else {
} else { contents = getXmindLegacyContent(file, res);
content = getXmindLegacyContent(file, res); }
} catch (Exception e) {
MSException.throwException(e.getMessage());
} finally {
// 删除生成的文件夹
if (res != null) {
File dir = new File(res);
FileUtil.deleteDir(dir);
}
// 删除零时文件
if (file != null)
file.delete();
} }
return contents;
// 删除生成的文件夹
File dir = new File(res);
FileUtil.deleteDir(dir);
JsonRootBean jsonRootBean = JSON.parseObject(content, JsonRootBean.class);
// 删除零时文件
if (file != null)
file.delete();
String json = (JSON.toJSONString(jsonRootBean, false));
if (StringUtils.isEmpty(content) || content.split("(?:tc:|tc|TC:|TC|tc|TC)").length == 1) {
MSException.throwException(Translator.get("import_xmind_not_found"));
}
if (!StringUtils.isEmpty(content) && content.split("(?:tc:|tc|TC:|TC|tc|TC)").length > 500) {
MSException.throwException(Translator.get("import_xmind_count_error"));
}
return json;
} }
public static JsonRootBean parseObject(MultipartFile multipartFile) throws DocumentException, ArchiveException, IOException { public static List<JsonRootBean> parseObject(MultipartFile multipartFile) throws DocumentException, ArchiveException, IOException {
String content = parseJson(multipartFile); List<String> contents = parseJson(multipartFile);
JsonRootBean jsonRootBean = JSON.parseObject(content, JsonRootBean.class); int caseCount = 0;
return jsonRootBean; List<JsonRootBean> jsonRootBeans = new ArrayList<>();
if (contents != null) {
for (String content : contents) {
caseCount += content.split("(?:tc:|tc|TC:|TC|tc|TC)").length;
JsonRootBean jsonRootBean = JSON.parseObject(content, JsonRootBean.class);
jsonRootBeans.add(jsonRootBean);
}
if (caseCount > 500) {
MSException.throwException(Translator.get("import_xmind_count_error"));
}
}
return jsonRootBeans;
} }
/** /**
* @return * @return
*/ */
public static String getXmindZenContent(File file, String extractFileDir) public static List<String> getXmindZenContent(File file, String extractFileDir)
throws IOException, ArchiveException { throws IOException, ArchiveException {
List<String> keys = new ArrayList<>(); List<String> keys = new ArrayList<>();
keys.add(xmindZenJson); keys.add(xmindZenJson);
Map<String, String> map = ZipUtils.getContents(keys, file, extractFileDir); Map<String, String> map = ZipUtils.getContents(keys, file, extractFileDir);
String content = map.get(xmindZenJson); String content = map.get(xmindZenJson);
content = XmindZen.getContent(content); return XmindZen.getContent(content);
return content;
} }
/** /**
* @return * @return
*/ */
public static String getXmindLegacyContent(File file, String extractFileDir) public static List<String> getXmindLegacyContent(File file, String extractFileDir)
throws IOException, ArchiveException, DocumentException { throws IOException, ArchiveException, DocumentException {
List<String> keys = new ArrayList<>(); List<String> keys = new ArrayList<>();
keys.add(xmindLegacyContent); keys.add(xmindLegacyContent);
@ -97,7 +104,7 @@ public class XmindParser {
String contentXml = map.get(xmindLegacyContent); String contentXml = map.get(xmindLegacyContent);
String commentsXml = map.get(xmindLegacyComments); String commentsXml = map.get(xmindLegacyComments);
String xmlContent = XmindLegacy.getContent(contentXml, commentsXml); List<String> xmlContent = XmindLegacy.getContent(contentXml, commentsXml);
return xmlContent; return xmlContent;
} }

View File

@ -5,61 +5,68 @@ import com.alibaba.fastjson.JSONObject;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class XmindZen { public class XmindZen {
/** /**
* @param jsonContent * @param jsonContent
* @return * @return
* @throws IOException * @throws IOException
* @throws DocumentException * @throws DocumentException
*/ */
public static String getContent(String jsonContent) { public static List<String> getContent(String jsonContent) {
JSONObject jsonObject = JSONArray.parseArray(jsonContent).getJSONObject(0); JSONArray jsonArray = JSONArray.parseArray(jsonContent);//.getJSONObject(0);
JSONObject rootTopic = jsonObject.getJSONObject("rootTopic"); List<String> contents = new ArrayList<>();
transferNotes(rootTopic); for (int i = 0; i < jsonArray.size(); i++) {
JSONObject children = rootTopic.getJSONObject("children"); JSONObject jsonObject = (JSONObject) jsonArray.get(i);
recursionChildren(children); JSONObject rootTopic = jsonObject.getJSONObject("rootTopic");
return jsonObject.toString(); transferNotes(rootTopic);
} JSONObject children = rootTopic.getJSONObject("children");
recursionChildren(children);
contents.add(jsonObject.toString());
}
return contents;
}
/** /**
* 递归转换children * 递归转换children
* *
* @param children * @param children
*/ */
private static void recursionChildren(JSONObject children) { private static void recursionChildren(JSONObject children) {
if (children == null) { if (children == null) {
return; return;
} }
JSONArray attachedArray = children.getJSONArray("attached"); JSONArray attachedArray = children.getJSONArray("attached");
if (attachedArray == null) { if (attachedArray == null) {
return; return;
} }
for (Object attached : attachedArray) { for (Object attached : attachedArray) {
JSONObject attachedObject = (JSONObject) attached; JSONObject attachedObject = (JSONObject) attached;
transferNotes(attachedObject); transferNotes(attachedObject);
JSONObject childrenObject = attachedObject.getJSONObject("children"); JSONObject childrenObject = attachedObject.getJSONObject("children");
if (childrenObject == null) { if (childrenObject == null) {
continue; continue;
} }
recursionChildren(childrenObject); recursionChildren(childrenObject);
} }
} }
private static void transferNotes(JSONObject object) { private static void transferNotes(JSONObject object) {
JSONObject notes = object.getJSONObject("notes"); JSONObject notes = object.getJSONObject("notes");
if (notes == null) { if (notes == null) {
return; return;
} }
JSONObject plain = notes.getJSONObject("plain"); JSONObject plain = notes.getJSONObject("plain");
if (plain != null) { if (plain != null) {
String content = plain.getString("content"); String content = plain.getString("content");
notes.remove("plain"); notes.remove("plain");
notes.put("content", content); notes.put("content", content);
} else { } else {
notes.put("content", null); notes.put("content", null);
} }
} }
} }