参考资料:http://feihu1117.iteye.com/blog/660289
二话不说,上代码。好吧。。。我承认不解析dtd而直接写成字符串是不好的,但是能抓老鼠的都是好猫嘛
package ejbModule.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
/**
* schema解析与xml构建类<br>
* 提供四个静态方法:<br>
* 1、SchemaUtil.parseXSD 解析<br>
* 2、SchemaUtil.createXML 创建<br>
* 3、SchemaUtil.updateXML 修改<br>
* 4、SchemaUtil.sortXMLNodes 排序
* @author LZY
*/
@SuppressWarnings("unchecked")
public class SchemaUtil
{
/** xml修改类型:增加节点 */
public final static String UPDATETYPE_ADD = "A";
/** xml修改类型:修改节点 */
public final static String UPDATETYPE_MODIFY = "M";
/** xml修改类型:删除节点 */
public final static String UPDATETYPE_DEL = "D";
/** schema定义的节点集合 */
private static List<XSDNode> list = null;
/**
* 解析XSD,返回数据节点对象列表
* @param xsd xml schema
* @param rootName 指定作为根节点的元素名称
* @return XSDNode元素列表
* @throws Exception
*/
public static List<XSDNode> parseXSD(String xsd, String rootName) throws Exception
{
try{
list = new ArrayList<XSDNode>();
Document doc = DocumentHelper.parseText(xsd);
Element rootElement = doc.getRootElement();
String path=XMLConstants.XSD_DEFAULT_NAMESPACE+ ":element[@name=\"" + rootName + "\"]";
Element targetElement = (Element) rootElement.selectSingleNode(path);
parseData(rootElement, targetElement, "/", targetElement.getPath());
return list;
}catch (Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* 根据schema和valueMap生成xml<br>
* XML生成规则:某节点的出现位置由valueMap的XPath路径(键)指定,不指定则默认按schema指定,即最少出现一次<br>
* 例:"/book/column[3]/id"表示第三个/book/column下的id节点<br>
* "/book/column[3]/@id"表示第三个/book/column的id属性
* @param xsd schema字符串
* @param rootName 根节点元素名
* @param valueMap "XPath路径,元素值"形式的键值对
* @return xml
*/
public static String createXML(String xsd,String rootName,HashMap<String, String> valueMap)
{
try
{
List<XSDNode> xsdNodeList = parseXSD(xsd,rootName);
Document document = DocumentHelper.createDocument();
//先根据valueMap生成xml
createNodesByValueMap(document,valueMap);
//然后使用schema补充无值节点
fillNodesByXSDNodes(document,xsdNodeList);
return document.asXML();
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
}
/**
* 根据valueMap修改xml,非SchemaUtil.UPDATETYPE_ADD情况可不传入xsd<br>
* XML修改规则:<br>
* 1、某位置节点的增加由valueMap的XPath路径(键)及(值)指定,默认按schema指定<br>
* 2、某位置节点的修改由valueMap的XPath路径(键)及(值)指定,不指定则不修改<br>
* 3、某位置节点的删除由valueMap的XPath路径(键)及(值)指定,含子节点全部删除<br>
* 例:"/book/column[3]/id"表示在第三个/book/column下增加id节点<br>
* @param xsd schema字符串
* @param xml 修改的xml字符串
* @param updateType 1、SchemaUtil.UPDATETYPE_ADD<br>
* 2、SchemaUtil.UPDATETYPE_MODIFY<br>
* 3、SchemaUtil.UPDATETYPE_DEL
* @param valueMap "XPath路径,元素值"形式的键值对
* @return xml
*/
public static String updateXML(String xsd,String xml,String updateType,HashMap<String, String> valueMap)
{
try
{
Document document = DocumentHelper.parseText(xml);
if(SchemaUtil.UPDATETYPE_ADD.equals(updateType))
{
List<XSDNode> xsdNodeList = parseXSD(xsd,document.getRootElement().getName());
createNodesByValueMap(document,valueMap);
fillNodesByXSDNodes(document,xsdNodeList);
}
else if(SchemaUtil.UPDATETYPE_MODIFY.equals(updateType))
{
Iterator iterator = valueMap.entrySet().iterator();
while(iterator.hasNext())
{
Entry<String, String> entry = (Entry<String, String>)iterator.next();
Node node = document.selectSingleNode(entry.getKey());
if(node == null)//无此节点时先创建节点
{
HashMap<String, String> tmpValueMap = new HashMap<String, String>();
tmpValueMap.put(entry.getKey(), entry.getValue());
List<XSDNode> xsdNodeList = parseXSD(xsd,document.getRootElement().getName());
createNodesByValueMap(document,tmpValueMap);
fillNodesByXSDNodes(document,xsdNodeList);
node = document.selectSingleNode(entry.getKey());
}
node.setText(entry.getValue());
}
}
else if(SchemaUtil.UPDATETYPE_DEL.equals(updateType))
{
List<Node> toDel = new ArrayList<Node>();
Iterator iterator = valueMap.entrySet().iterator();
while(iterator.hasNext())
{
Entry<String, String> entry = (Entry<String, String>)iterator.next();
Node node = document.selectSingleNode(entry.getKey());
if(node != null) toDel.add(node);
}
iterator = toDel.iterator();
while(iterator.hasNext())
{
Node node = (Node)iterator.next();
node.getParent().remove(node);
}
}
return document.asXML();
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
}
/**
* 对给出的XML,指定进行排序的节点和排序方式,进行排序<br>
* 调用例:sortXMLNodes(xml, "/book/column", "order", true)
* @param xml 进行排序的XML
* @param xPath 进行排序的节点集,其XPath路径
* @param cmpName 排序依据值其元素XPath,可为属性或节点名称
* @param bIsAesc 升序(true)/降序(false)
* @return 排序结束后的xml
*/
public static String sortXMLNodes(String xml,String xPath,String cmpName,boolean bIsAesc)
{
try
{
Document document = DocumentHelper.parseText(xml);
List<Element> nodes = document.selectNodes(xPath,cmpName);
if(bIsAesc == false)
Collections.reverse(nodes); //降序
for(Element e : nodes)
{
Element parent = e.getParent();
parent.remove(e);
parent.add(e);
}
return document.asXML();
}
catch (Exception e)
{
e.printStackTrace();
return "";
}
}
/**
* 根据ValueMap创建XML节点
* @param document xml dom
* @param valueMap 值集合
* @throws Exception
*/
private static void createNodesByValueMap(Document document, HashMap<String, String> valueMap) throws Exception
{
Iterator iterator = valueMap.entrySet().iterator();
while(iterator.hasNext())
{
Entry<String, String> entry = (Entry<String, String>)iterator.next();
String key = entry.getKey();
StringTokenizerCloneable tokens = new StringTokenizerCloneable(key, "/");
Element parent = document.getRootElement();
String name = tokens.nextToken();
if (parent == null) parent = document.addElement(name);
Element element = null;
while (tokens.hasMoreTokens())
{
name = tokens.nextToken();
if (name.indexOf(':') > 0)
{
element = parent.element(parent.getQName(name));
}
else if(name.indexOf("@") == 0)
{
name = name.substring(1);
parent.addAttribute(name, "");
break;
}
else
{
element = parent.element(name);
}
if (element == null)
{
Pattern pa = Pattern.compile("\\[.*?\\]");
Matcher ma = pa.matcher(name);
if(ma.find())
{
String pos = ma.group();//位置号
name = name.substring(0,name.indexOf("["));//节点名
List<Element> elList = parent.elements(name);
int iElNum = elList == null?0:elList.size();
int iPos = 0;
try
{
iPos = Integer.valueOf(pos.substring(1,pos.length() - 1));
}
catch (Exception e){iPos = iElNum;}
int iDiff = iPos - iElNum;//给定位置与实际节点数的差
while(iDiff > 0)
{//补充缺少节点
parent.addElement(name);//创建同名节点
iDiff --;
}
elList = parent.elements(name);
element = elList.get(iPos - 1);
}
else
element = parent.addElement(name);
}
parent = element;
}
document.selectSingleNode(key).setText(entry.getValue());
}
}
/**
* 根据schema元素填充无值XML节点
* @param document xml dom
* @param xsdNodeList schema元素集合
* @throws Exception
*/
private static void fillNodesByXSDNodes(Document document, List<XSDNode> xsdNodeList) throws Exception
{
for(int i=0;i < xsdNodeList.size();i++)
{
String path = xsdNodeList.get(i).getXPath();
StringTokenizerCloneable tokens = new StringTokenizerCloneable(path, "/");
Element parent = document.getRootElement();
String name = tokens.nextToken();
if (parent == null) parent = document.addElement(name);
if (tokens.hasMoreTokens()) fillNodes(parent,tokens,tokens.nextToken());
}
}
/**
* 递归填充无值XML节点
* @param parent 父节点
* @param tokens 记号
* @param name 当前节点名
* @throws Exception
*/
private static void fillNodes(Element parent,StringTokenizerCloneable tokens,String name) throws Exception
{
if(name.indexOf("@") == 0)
{
name = name.substring(1);
if(parent.attribute(name) == null) parent.addAttribute(name, "");
return;
}
List<Element> elements = null;
elements = getElements(parent,name);
if (elements == null || elements.size() == 0)
{
parent.addElement(name);
elements = getElements(parent,name);
}
else
{//调整顺序,把已有节点放到最后
int iEl = elements.size();
for(int i=0;i < iEl;i++)
{
Element element = elements.get(0).createCopy();
parent.remove(elements.get(0));
parent.add(element);
//修改后取回引用
elements = getElements(parent,name);
}
}
if (tokens.hasMoreTokens())
{
for(int i=0;i < elements.size();i++)
{
StringTokenizerCloneable clone = (StringTokenizerCloneable)tokens.clone();
fillNodes(elements.get(i), clone, clone.nextToken());
}
}
}
/**
* 获取Element集合
* @param parent 父节点
* @param name Element节点名
* @return Element集合
*/
private static List<Element> getElements(Element parent,String name) throws Exception
{
List<Element> elements = null;
if (name.indexOf(':') > 0)
{
elements = parent.elements(parent.getQName(name));
}
else
{
elements = parent.elements(name);
}
return elements;
}
/**
* 转换XSD的数据节点,生成XSDNode对象
* @param rootElement 根元素
* @param element 当前元素
* @param xPath 当前元素在xml中的xpath路径
* @param xsdPath 当前xsd元素在schema中的xpath路径
*/
private static void parseData(Element rootElement,Element element, String xPath, String xsdPath) throws Exception
{
String nodeRef = element.attributeValue("ref");
if(nodeRef != null)//存在ref属性的引用情况
{
Element refElement = (Element)rootElement.selectSingleNode(XMLConstants.XSD_DEFAULT_NAMESPACE + ":element[@name=\""+ nodeRef +"\"]");
xsdPath = refElement.getPath();
element = refElement;
}
//获取节点name属性
String nodeName = element.attributeValue("name");
//组装xml文档中节点的XPath
xPath += nodeName;
//组装下一个element元素的XPath
String cpxXsdPath = xsdPath + "[@name=\"" + nodeName + "\"]" + "/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":complexType/";
String currentXsdPath = cpxXsdPath
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":sequence/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":element";
//自定义复杂类型
if (element.attribute("type") != null && element.attribute("type").getText().indexOf(XMLConstants.XSD_DEFAULT_NAMESPACE + ":") < 0)
{
Element typeElement = (Element)rootElement.selectSingleNode(XMLConstants.XSD_DEFAULT_NAMESPACE + ":complexType[@name=\""+ element.attribute("type").getText() +"\"]");
xsdPath = typeElement.getPath();
cpxXsdPath = xsdPath + "[@name=\"" + nodeName + "\"]" + "/";
currentXsdPath = cpxXsdPath
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":sequence/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":element";
}
parseAttr(rootElement,cpxXsdPath,xPath);
//查找该节点下所有的element元素
List<Node> elementNodes = element.selectNodes(currentXsdPath);
if(elementNodes != null && elementNodes.size() > 0)
{//如果下面还有element,说明不是叶子
Iterator<Node> nodes = elementNodes.iterator();
while (nodes.hasNext())
{
if (!xPath.endsWith("/"))
{
xPath += "/";
}
Element ele = (Element) nodes.next();
parseData(rootElement, ele, xPath, currentXsdPath);
}
}
else
{
//获取节点类型属性
String nodeType = "";
Attribute type = element.attribute("type");
if (type != null) nodeType = type.getText();
else
{//该element为叶子
String spath = xsdPath + "[@name=\"" + nodeName + "\"]/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleType/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":restriction";
Element typeNode = (Element) element.selectSingleNode(spath);
if (typeNode == null)//另一方式
{
spath = xsdPath + "[@name=\"" + nodeName + "\"]/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":complexType/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleContent/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":extension";
typeNode = (Element) element.selectSingleNode(spath);
}
if (typeNode != null)
{
Attribute base = typeNode.attribute("base");
if (base != null) nodeType = base.getText();
}
}
XSDNode xsdNode = new XSDNode();
xsdNode.setName(nodeName);
xsdNode.setXPath(xPath);
xsdNode.setType(nodeType);
list.add(xsdNode);
}
}
/**
* 解析节点属性
* @param rootElement 根节点
* @param cpxXsdPath 复杂类型节点路径
*/
private static void parseAttr(Element rootElement,String cpxXsdPath,String xPath) throws Exception
{
String attrPath1 = cpxXsdPath + XMLConstants.XSD_DEFAULT_NAMESPACE + ":attribute";
List<Element> attrList = rootElement.selectNodes(attrPath1);
if(attrList != null && attrList.size() > 0)
{
for(int i=0;i<attrList.size();i++)
{
addAttr(rootElement,attrList.get(i),xPath);
}
}
String attrPath2 = cpxXsdPath
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleContent/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":extension/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":attribute";
attrList = rootElement.selectNodes(attrPath2);
if(attrList != null && attrList.size() > 0)
{
for(int i=0;i<attrList.size();i++)
{
addAttr(rootElement,attrList.get(i),xPath);
}
}
}
/**
* 把节点属性加入元素列表
* @param rootElement 根节点
* @param element 属性描述节点
* @param xPath 属性所属节点xPath
*/
private static void addAttr(Element rootElement,Element element,String xPath) throws Exception
{
String nodeRef = element.attributeValue("ref");
if(nodeRef != null)//存在ref属性的引用情况
{
Element refElement = (Element)rootElement.selectSingleNode(XMLConstants.XSD_DEFAULT_NAMESPACE + ":attribute[@name=\""+ nodeRef +"\"]");
element = refElement;
}
String name = element.attributeValue("name");
//获取节点类型属性
String nodeType = "";
Attribute type = element.attribute("type");
if (type != null) nodeType = type.getText();
else
{//该element为叶子
String spath = element.getPath() + "/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleType/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":restriction";
Element typeNode = (Element) element.selectSingleNode(spath);
if (typeNode == null)//另一方式
{
spath = element.getPath() + "/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":complexType/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleContent/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":extension";
typeNode = (Element) element.selectSingleNode(spath);
}
if (typeNode != null)
{
Attribute base = typeNode.attribute("base");
if (base != null) nodeType = base.getText();
}
}
XSDNode xsdNode = new XSDNode();
xsdNode.setName(name);
xsdNode.setXPath(xPath + "/@" + name);
xsdNode.setType(nodeType);
list.add(xsdNode);
}
/**
* xsd元素对象
*/
public static class XSDNode
{
/** 元素名称 */
private String name;
/** 元素XPath */
private String xPath;
/** 元素类型 */
private String type;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getXPath()
{
return xPath;
}
public void setXPath(String path)
{
xPath = path;
}
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
}
/**
* xsd固定名称字符串
*/
private static class XMLConstants
{
/** xml编码 */
public static final String ENCODING = "UTF-8";
/** xsd默认命名空间 */
public static final String XSD_DEFAULT_NAMESPACE = "xs";
/** xsd复合类型节点 */
public static final String XSD_COMPLEX_TYPE = "complexType";
/** xsd序列节点 */
public static final String XSD_SEQUENCE = "sequence";
/** xsd元素节点 */
public static final String XSD_ELEMENT = "element";
/** xsd注解节点 */
public static final String XSD_ANNOTATION = "annotation";
/** xsd注解文档节点 */
public static final String XSD_DOCUMENTATION = "documentation";
/** xsd简单类型节点 */
public static final String XSD_SIMPLE_TYPE = "simpleType";
/** xsd限制节点 */
public static final String XSD_RESTRICTION = "restriction";
/** xsd name属性 */
public static final String XSD_ATTRIBUTE_NAME = "name";
/** xsd type属性 */
public static final String XSD_ATTRIBUTE_TYPE = "type";
/** xsd base属性 */
public static final String XSD_ATTRIBUTE_base = "base";
}
/**
* 可复制对象的StringTokenizer类
*/
private static class StringTokenizerCloneable extends StringTokenizer implements Cloneable
{
public StringTokenizerCloneable(String str, String delim, boolean returnDelims)
{
super(str,delim,returnDelims);
}
public StringTokenizerCloneable(String str, String delim)
{
super(str, delim);
}
public StringTokenizerCloneable(String str)
{
super(str);
}
public Object clone()
{
StringTokenizerCloneable o = null;
try
{
o = (StringTokenizerCloneable)super.clone();
}
catch(CloneNotSupportedException e)
{
e.printStackTrace();
}
return o;
}
}
}