package org.test4j.spec.scenario.xmlparser;
import java.util.List;
import org.dom4j.CDATA;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.test4j.spec.scenario.xmlparser.entity.ScenarioMethod;
import org.test4j.spec.scenario.xmlparser.entity.StoryScenario;
import org.test4j.spec.scenario.xmlparser.entity.TemplateMethod;
import org.test4j.spec.util.XmlHelper;
import org.test4j.spec.util.XmlHelper.MethodNode;
import org.test4j.tools.commons.StringHelper;
/**
* xml形式的用例文件构建器
*
* @author darui.wudr 2012-7-12 下午1:59:41
*/
public class StoryXmlBuilder implements StoryQName {
/**
* 新增用例场景
*
* @param parent
* @param scenario
*/
public static String addScenario(Element parent, StoryScenario scenario) {
Element element = parent.addElement(nodeScenario);
Element scenarioDescription = element.addElement(nodeDescription);
String desc = filteCDATA(scenario.getDescription());
CDATA cdata = DocumentHelper.createCDATA(desc);
scenarioDescription.clearContent();
scenarioDescription.add(cdata);
modifyScenario(element, scenario);
String path = StoryXmlBuilder.getXPathID(element);
return path;
}
/**
* 往document文档中追加一个场景节点
*
* @param document
* @param scenario
*/
public static String addScenario(Document document, StoryScenario scenario) {
Element story = ((Element) document.selectSingleNode(StoryQName.xpathRoot));
String path = StoryXmlBuilder.addScenario(story, scenario);
return path;
}
/**
* 修改用例场景
*
* @param scenarioNode
* @param scenario
*/
public static void modifyScenario(Element scenarioNode, StoryScenario scenario) {
scenarioNode.addAttribute(attrName, scenario.getScenarioName());
scenarioNode.addAttribute(attrSkip, String.valueOf(scenario.isSkip()));
Element descNode = (Element) scenarioNode.selectSingleNode(nodeDescription);
if (descNode == null) {
descNode = scenarioNode.addElement(StoryQName.nodeDescription);
}
String desc = filteCDATA(scenario.getDescription());
CDATA cdata = DocumentHelper.createCDATA(desc);
descNode.clearContent();
descNode.add(cdata);
}
/**
* 新增用例步骤
*
* @param parent
* @param method
*/
public static String addScenarioMethod(Element parent, ScenarioMethod method) {
Element element = parent.addElement(nodeScenarioMethod);
modifyScenarioMethod(element, method);
String path = StoryXmlBuilder.getXPathID(element);
return path;
}
/**
* 修改用例步骤
*
* @param methodNode
* @param method
*/
public static void modifyScenarioMethod(Element methodNode, ScenarioMethod method) {
// 这一行必须在最前面,防止内容解析出错时把相应的节点内容先清空了
List<MethodNode> nodes = XmlHelper.parseMethodContext(method.getInitialText());
methodNode.addAttribute(attrName, method.getMethodName());
methodNode.addAttribute(attrType, method.getMethodType());
methodNode.addAttribute(attrSkip, String.valueOf(method.isSkip()));
addMethodChildren(methodNode, nodes);
}
/**
* 修改模板方法
*
* @param templateNode
* @param template
*/
public static void modifyTemplateMethod(Element templateNode, TemplateMethod template) {
List<MethodNode> nodes = XmlHelper.parseMethodContext(template.getInitialText());
templateNode.addAttribute(attrName, template.getMethodName());
templateNode.addAttribute(attrType, template.getMethodType());
addMethodChildren(templateNode, nodes);
}
static void addMethodChildren(Element method, List<MethodNode> children) {
method.clearContent();
for (MethodNode item : children) {
if (item.isPara()) {
Element para = DocumentHelper.createElement("para");
para.addAttribute("name", item.getParaName());
String value = filteCDATA(item.getText());
CDATA cdata = DocumentHelper.createCDATA(value);
para.add(cdata);
method.add(para);
} else {
String text = filteCDATA(item.getText());
CDATA cdata = DocumentHelper.createCDATA(text);
method.add(cdata);
}
}
}
/**
* 新建用例故事
*
* @param description
* @return
*/
public static Document createStory(String description) {
StringBuilder buff = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
buff.append("<story>\n");
String desc = filteCDATA(description);
buff.append(String.format("\t<description>%s</description>\n", desc));
buff.append("\t<templates>\n\t</templates>\n");
buff.append("\t<scenarios>\n\t</scenarios>\n");
buff.append("</story>");
Document document = XmlHelper.buildFromString(buff.toString());
return document;
}
/**
* 修改用例描述
*
* @param textNode
* @param text
*/
public static void modifyStoryDescription(Element textNode, String text) {
String desc = filteCDATA(text);
CDATA cdata = DocumentHelper.createCDATA(desc);
textNode.clearContent();
textNode.add(cdata);
}
/**
* 在xml文档中移除xpath指定的节点
*
* @param document
* @param xPathID
*/
public static void removeElement(Document document, String xPathID) {
Element node = (Element) document.selectSingleNode(xPathID);
if (node != null) {
node.detach();
}
}
/**
* 标准化节点的xpath表达式
*
* @param xpath
* @return
*/
public static String convertPathID(String xpath) {
String[] items = xpath.split("/");
StringBuilder buff = new StringBuilder("");
for (String item : items) {
buff.append("/").append(item);
if (item.equals(StoryQName.nodeTemplateMethod) || item.equals(StoryQName.nodeScenarioMethod)
|| item.equals(StoryQName.nodeScenario)) {
buff.append("[1]");
}
}
return buff.toString().substring(1);
}
/**
* 返回节点的标准化xpath表达式
*
* @param node
* @return
*/
public static String getXPathID(Element node) {
String path = node.getUniquePath();
String xpath = convertPathID(path);
return xpath;
}
/**
* 新增模板方法
*
* @param parent
* @param template
*/
public static String addTemplateMethod(Element parent, TemplateMethod template) {
Element element = parent.addElement(nodeTemplateMethod);
modifyTemplateMethod(element, template);
String path = StoryXmlBuilder.getXPathID(element);
return path;
}
/**
* 往document文档中追加一个模板方法
*
* @param document
* @param template
*/
public static String addTemplateMethod(Document document, TemplateMethod template) {
Element templatesNode = ((Element) document.selectSingleNode(StoryQName.xpathTemplate));
if (templatesNode == null) {
templatesNode = document.getRootElement().addElement(StoryQName.nodeMethodTemplate);
}
String path = StoryXmlBuilder.addTemplateMethod(templatesNode, template);
return path;
}
/**
* 往文档父节点parentXPath下追加一个子节点
*
* @param document
* @param parentXPathID
* @param method
*/
public static String addScenarioMethod(Document document, String parentXPathID, ScenarioMethod method) {
Element parent = (Element) document.selectSingleNode(parentXPathID);
if (parent == null) {
return parentXPathID;
}
String path = addScenarioMethod(parent, method);
return path;
}
/**
* 更新指定文档中的节点内容
*
* @param document
* @param mimeXPathID
* @param method
*/
public static String uptScenarioMethod(Document document, String mimeXPathID, ScenarioMethod method) {
Element myself = (Element) document.selectSingleNode(mimeXPathID);
if (myself == null) {
return mimeXPathID;
}
modifyScenarioMethod(myself, method);
return mimeXPathID;
}
/**
* 在文档brother节点前插入一个新节点
*
* @param document
* @param brother
* @param method
*/
@SuppressWarnings("unchecked")
public static String insScenarioMethod(Document document, String brotherXPathID, ScenarioMethod method) {
Element brother = (Element) document.selectSingleNode(brotherXPathID);
if (brother == null) {
return brotherXPathID;
}
int index = brother.getParent().elements().indexOf(brother);
Element newNode = (Element) brother.clone();
modifyScenarioMethod(newNode, method);
brother.getParent().elements().add(index, newNode);
String path = StoryXmlBuilder.getXPathID(newNode);
return path;
}
/**
* 更新文档中xpathID节点的场景内容
*
* @param document
* @param xpathID
* @param scenario
*/
public static String uptStoryScenario(Document document, String xpathID, StoryScenario scenario) {
if (!xpathID.startsWith(StoryQName.xpathScenario) || xpathID.contains(StoryQName.nodeScenarioMethod)) {
return xpathID;
}
Element scenarioNode = (Element) document.selectSingleNode(xpathID);
if (scenarioNode == null) {
return xpathID;
}
StoryXmlBuilder.modifyScenario(scenarioNode, scenario);
return xpathID;
}
/**
* 复制xpathID的用例场景内容(包括具体步骤)
*
* @param document
* @param xpathID
* @param scenario
*/
public static String cpyStoryScenario(Document document, String xpathID, StoryScenario scenario) {
if (!xpathID.startsWith(StoryQName.xpathScenario) || xpathID.contains(StoryQName.nodeScenarioMethod)) {
return xpathID;
}
Element oldScenario = (Element) document.selectSingleNode(xpathID);
if (oldScenario == null) {
return xpathID;
}
String pathID = StoryXmlBuilder.addScenario(document, scenario);
Element newScenario = (Element) document.selectSingleNode(pathID);
StoryXmlBuilder.cpyScenarioSteps(oldScenario, newScenario);
return pathID;
}
/**
* 从场景oldScenario拷贝步骤到newScenario场景
*
* @param oldScenario
* @param newScenario
*/
@SuppressWarnings("unchecked")
private static void cpyScenarioSteps(Element oldScenario, Element newScenario) {
List<Element> methods = oldScenario.selectNodes(StoryQName.nodeScenarioMethod);
for (Element method : methods) {
Element newMethod = method.createCopy();
newScenario.add(newMethod);
}
}
/**
* 往文档场景列表parentID中追加一个子节点scenario
*
* @param document
* @param parentID
* @param scenario
*/
public static String addStoryScenario(Document document, String parentID, StoryScenario scenario) {
if (!parentID.equals(StoryQName.nodeStory)) {
return parentID;
}
Element scenariosNode = (Element) document.selectSingleNode(StoryQName.xpathRoot);
String pathID = StoryXmlBuilder.addScenario(scenariosNode, scenario);
return pathID;
}
/**
* 更新文档中模板方法内容
*
* @param document
* @param xpathID
* @param method
*/
public static String uptTemplateMethod(Document document, String xpathID, TemplateMethod method) {
if (!xpathID.startsWith(StoryQName.xpathTemplateMethod)) {
return xpathID;
}
Element templateNode = (Element) document.selectSingleNode(xpathID);
if (templateNode == null) {
return xpathID;
}
StoryXmlBuilder.modifyTemplateMethod(templateNode, method);
return xpathID;
}
/**
* 在文档中新增一个模板节点
*
* @param document
* @param xpathID
* @param method
*/
public static String addTemplateMethod(Document document, String xpathID, TemplateMethod method) {
if (!xpathID.equals(StoryQName.xpathTemplate)) {
return xpathID;
}
String methodPathID = StoryXmlBuilder.addTemplateMethod(document, method);
return methodPathID;
}
/**
* 更新文档中xpathID节点的场景内容<br>
*
* @param document
* @param xpathID
* @param scenario
*/
public static void uptStoryDescription(Document document, String description) {
Element node = (Element) document.selectSingleNode(StoryQName.xpathDescription);
if (node == null) {
node = document.getRootElement().addElement(StoryQName.nodeDescription);
}
StoryXmlBuilder.modifyStoryDescription(node, description);
}
/**
* 转换<![DATA[ 和 ]]>
*
* @param text
* @return
*/
public static String filteCDATA(String text) {
if (StringHelper.isBlankOrNull(text)) {
return "";
} else {
return text.replaceAll("\\]\\]>", "]]>").replaceAll("<!\\[CDATA\\[", "<![CDATA[");
}
}
}