在比较大的项目中,我们有时会用到服务这个概念,一些服务会以xml的形式返回结果,这个时候就要对XML进行解析,但很多时候,我们对服务提供的XML结构不甚了解,就算了解了,如果服务被修改XML结构被改变,这个时候以前写好的解析XML的方法就会出现紊乱,如何解决这个问题呢?其实标准的服务在提供给用户XML的时候会提供给用户对应的XML描述文件,这就是XSD文件,对此文件进行解析后再利用解析后的XSD文件对XML进行解析,这样即使服务节点变了,后台的代码也能正确解析当前服务返回的XML文件。XSD文件的解析方法如下:
静态变量类:
package test;
public class XMLConstants {
// 默认数据节点,设置为空则认为根目录为默认数据节点
public static final String MESSAGE = "Features";
//xml编码
public static final String ENCODING = "UTF-8";
// xsd默认命名空间,设置为空则没有默认命名空间
public static final String XSD_DEFAULT_NAMESPACE = "xs";
// xsd定义的默认数据节点,设置为空则认为根目录为默认数据节点
public static final String XSD_DEFAULT_DATANODE = "Features";
// 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";
// 用来描述xsd中的unbounded节点信息
public static final String XSD_UNBOUNDED = "[unbounded]";
public static final String XSD_UNBOUNDED_REPLATE = "\\[unbounded\\]";
public static final String XSL_ELEMENT_FOREACH = "for-each";
public static final String XSL_ELEMENT_SELECT = "select";
/** ************* 创建xslt基础变量配置 ******************* */
public static final String STYLESHEET = "stylesheet";
public static final String VERSION = "version";
public static final String VERSIONNUM = "1.0";
public static final String NAMESPACE = "xsl";
public static final String NAMESPACEADDRESS = "http://www.w3.org/1999/XSL/Transform";
public static final String TEMPLATE = "template";
public static final String MATCH = "match";
public static final String APPLYTEMPLATES = "apply-templates";
public static final String VALUEOF = "value-of";
public static final String SELECT = "select";
public static final String XMLENCODING = "UTF-8";
public static final String ROOTSPER = "/";
public static final String DOUBELROOTSPER = "//";
public static final String SPER = ":";
}
XSD节点对象类:
package test;
public class XSDNode {
// 节点名称
private String name;
// 节点XPath
private String xPath;
// 节点描述
private String annotation;
// 节点类型
private String type;
// 业务用路径,描述路径中的unbound节点
private String unboundedXpath;
private String isUnbounded;
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 getAnnotation() {
return annotation;
}
public void setAnnotation(String annotation) {
this.annotation = annotation;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUnboundedXpath() {
return unboundedXpath;
}
public void setUnboundedXpath(String unboundedXpath) {
this.unboundedXpath = unboundedXpath;
}
public String getIsUnbounded() {
return isUnbounded;
}
public void setIsUnbounded(String isUnbounded) {
this.isUnbounded = isUnbounded;
}
}
XSD解析方法类:
package test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
public class XSDReader {
private List<XSDNode> list = new ArrayList<XSDNode>();
/**
* 解析XSD,返回数据节点对象列表
*
* @param xsd
* @return
* @throws Exception
*/
public List<XSDNode> paserXSD(String xsd) throws Exception {
SAXReader saxReader = new SAXReader();
// ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xsd.getBytes(BaseConstants.XM LENCODING));
Document doc = saxReader.read(xsd);
Element element = doc.getRootElement();
String basePath = null;
Element dataElement = null;
if("".equals(XMLConstants.XSD_DEFAULT_NAMESPACE)){
if("".equals(XMLConstants.MESSAGE)){
dataElement = element;
}else{
basePath = "//element[@name=\"" + XMLConstants.MESSAGE + "\"]";
dataElement = (Element) element.selectSingleNode(basePath);
}
}else{
basePath = "//" + XMLConstants.XSD_DEFAULT_NAMESPACE + ":element[@name=\"" + XMLConstants.MESSAGE + "\"]";
dataElement = (Element) element.selectSingleNode(basePath);
}
String elementPath = null;
if("".equals(XMLConstants.XSD_DEFAULT_NAMESPACE)){
elementPath = "//element";
}else{
elementPath = "//" + XMLConstants.XSD_DEFAULT_NAMESPACE + ":element";
}
paseData(dataElement, "//", elementPath, "//");
return list;
}
/**
* 转换XSD的数据节点,生成XSDNode对象
*
* @param element
* @param xPath
* @param xsdPath
* @param unboundedXpath
*/
public void paseData(Element element, String xPath, String xsdPath, String unboundedXpath) {
if(element==null) return;
// 获取节点name属性
String nodeName = element.attributeValue("name");
// 组装xml文档中节点的XPath
xPath += nodeName;
unboundedXpath += nodeName;
// 并列多节点限制属性
String maxOccurs = element.attributeValue("maxOccurs");
if (maxOccurs != null && !"1".equals(maxOccurs) && !("//" + XMLConstants.MESSAGE + "").equals(xPath)) {// 节点可以有多个
unboundedXpath += XMLConstants.XSD_UNBOUNDED;
}
// 组装下一个element元素的XPath
String currentXsdPath = xsdPath + "[@name=\"" + nodeName + "\"]" + "/" + XMLConstants.XSD_DEFAULT_NAMESPACE
+ ":complexType/" + XMLConstants.XSD_DEFAULT_NAMESPACE + ":sequence/" + XMLConstants.XSD_DEFAULT_NAMESPACE
+ ":element";
// 查找该节点下所有的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 += "/";
unboundedXpath += "/";
}
Element ele = (Element) nodes.next();
paseData(ele, xPath, currentXsdPath, unboundedXpath);
}
} else { // 该element为叶子
XSDNode xsdNode = new XSDNode();
// 获取注释节点
String annotation = "";
Node annotationNode = element
.selectSingleNode(xsdPath + "[@name=\"" + nodeName + "\"]/" + XMLConstants.XSD_DEFAULT_NAMESPACE
+ ":annotation/" + XMLConstants.XSD_DEFAULT_NAMESPACE + ":documentation");
if (annotationNode != null)
annotation = annotationNode.getText();
// 获取节点类型属性
String nodeType = "";
Attribute type = element.attribute("type");
if (type != null){
nodeType = type.getText();
}else {
String spath = xsdPath + "[@name=\"" + nodeName + "\"]/" + XMLConstants.XSD_DEFAULT_NAMESPACE + ":simpleType/"
+ XMLConstants.XSD_DEFAULT_NAMESPACE + ":restriction";
Element typeNode = (Element) element.selectSingleNode(spath);
if (typeNode != null) {
Attribute base = typeNode.attribute("base");
if (base != null)
nodeType = base.getText();
}
}
xsdNode.setName(nodeName);
xsdNode.setXPath(xPath);
xsdNode.setAnnotation(annotation);
xsdNode.setType(nodeType);
xsdNode.setUnboundedXpath(unboundedXpath);
list.add(xsdNode);
}
}
public static void main(String[] args) {
try {
String realPath = XSDReader.class.getResource("/").getPath();
XSDReader xsdReader = new XSDReader();
List<XSDNode> nodes = xsdReader.paserXSD(realPath+"/feature.xsd");
for (XSDNode node : nodes) {
System.out.println(node.getUnboundedXpath());
}
} catch (Exception ex){
ex.printStackTrace();
}
}
}
示例的XSD文件:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Features">
<xs:annotation>
<xs:documentation>QueryChange</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="networkName"/>
<xs:element name="FeatureCollection" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="featureMember" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Road">
<xs:complexType>
<xs:sequence>
<xs:element name="lineId"/>
<xs:element name="lineName"/>
<xs:element name="passNodeIds"/>
<xs:element name="passNodeNames"/>
<xs:element name="passNodeCoordinates"/>
<xs:element name="geometry">
<xs:complexType>
<xs:sequence>
<xs:element ref="gml:LineString"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>