XMLSchema(XSD)解析类

参考资料: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;
	    }
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值