SCHEMA验证

Posted on 2010-10-28 14:02  胡安峰  阅读(627)  评论(0编辑  收藏  举报

  辅导同事让我写一个能够简单验证XML文的程序。由于只要求能xml文里有开始有结束标签就算正确的格式。我在网上找了很长时间也没有找到这样的工具和程序。不过发现一个可以严格限制xml文的 SCHEMA ,不过这个需要用到dom4j 源代码如下。感觉写的非常好。

  1. package cn.com.starit.DB;   
  2.   
  3. import java.io.File;   
  4. import java.io.FileWriter;   
  5.   
  6. import javax.xml.parsers.SAXParser;   
  7. import javax.xml.parsers.SAXParserFactory;   
  8.   
  9. import org.dom4j.Document;   
  10. import org.dom4j.io.OutputFormat;   
  11. import org.dom4j.io.SAXReader;   
  12. import org.dom4j.io.SAXValidator;   
  13. import org.dom4j.io.XMLWriter;   
  14. import org.dom4j.util.XMLErrorHandler;   
  15.   
  16. public class ValidateXML {   
  17.  public static void validateXMLByXSD(String xsdFileName,String xmlFileName) {   
  18.         try {   
  19.             //创建默认的XML错误处理器   
  20.             XMLErrorHandler errorHandler =  new XMLErrorHandler();   
  21.               
  22.             //获取基于 SAX 的解析器的实例   
  23.             SAXParserFactory factory = SAXParserFactory.newInstance();   
  24.             //解析器在解析时验证 XML 内容。   
  25.             factory.setValidating(true);   
  26.             //指定由此代码生成的解析器将提供对 XML 名称空间的支持。   
  27.             factory.setNamespaceAware(true);   
  28.             //使用当前配置的工厂参数创建 SAXParser 的一个新实例。   
  29.             SAXParser parser = factory.newSAXParser();   
  30.             //创建一个读取工具   
  31.             SAXReader xmlReader = new SAXReader();   
  32.             //获取要校验xml文档实例   
  33.             Document xmlDocument = (Document) xmlReader.read(new File(xmlFileName));   
  34.             //设置 XMLReader 的基础实现中的特定属性。核心功能和属性列表可以在 [url]http://sax.sourceforge.net/?selected=get-set[/url] 中找到。   
  35.             parser.setProperty(   
  36.                     "http://java.sun.com/xml/jaxp/properties/schemaLanguage",   
  37.                     "http://www.w3.org/2001/XMLSchema");   
  38.             parser.setProperty(   
  39.                     "http://java.sun.com/xml/jaxp/properties/schemaSource",   
  40.                     "file:" + xsdFileName);   
  41.             //创建一个SAXValidator校验工具,并设置校验工具的属性   
  42.             SAXValidator validator = new SAXValidator(parser.getXMLReader());   
  43.             //设置校验工具的错误处理器,当发生错误时,可以从处理器对象中得到错误信息。   
  44.             validator.setErrorHandler(errorHandler);                       
  45.                
  46.             //校验   
  47.             validator.validate(xmlDocument);   
  48.             OutputFormat format = OutputFormat.createPrettyPrint();   
  49.             format.setEncoding("UTF-8");    
  50.             XMLWriter writer = new XMLWriter( new  
  51.             FileWriter(new File("d://err.xml")), format);   
  52.   
  53.             //  TODO     XMLWriter writer = new XMLWriter(OutputFormat.createPrettyPrint());   
  54.             //如果错误信息不为空,说明校验失败,打印错误信息   
  55.             if (errorHandler.getErrors().hasContent()) {   
  56.                 System.out.println("XML文件通过XSD文件校验失败!");   
  57.                 // ** 将document中的内容写入文件中 *//*   
  58.                 writer.write(errorHandler.getErrors()); //writer.write(parse(document));               
  59.                 writer.close();                  
  60.             } else {   
  61.                 System.out.println("Good! XML文件通过XSD文件校验成功!");   
  62.             }   
  63.         } catch (Exception ex) {   
  64.             System.out.println("XML文件: " + xmlFileName + " 通过XSD文件:" + xsdFileName + "检验失败。/n原因: " + ex.getMessage());   
  65.             ex.printStackTrace();   
  66.         }   
  67.     }   
  68.   
  69.   public static void main(String[] args) {   
  70.        String xsdpath = "e://test1.xsd";   
  71.        String xmlpath = "e://test1.xml";   
  72.        validateXMLByXSD(xsdpath,xmlpath);   
  73.   }   
  74.   
  75. ///************验证字符串[xml 字符串 转化成 输入流] start****************/   
  76. //   
  77. //// xmlMsg为xml文档<?xml version="1.0" encoding="GBK"?>........   
  78. //InputStream in = new ByteArrayInputStream(xmlMsg);    
  79. //   
  80. //然后将上面的reader.read("message.xml") 改为 reader.read(in)就OK了。   
  81. //   
  82. ///************验证字符串[xml 字符串 转化成 输入流] end ****************/   
  83. }   

不过还是遇到一个问题。我们的xml文里(其实没有我把小写L看成1)有数字节点,我就想到可以用正则表达式来替换啊~可惜我对正则很陌生。怎么办上网查找看有没有能够快速入门的。上网找了半天,终于找到一个可以三十分钟就可以入门的教程。写的确实不错。不过我感觉看完了还是一头雾水。不过基本的概念已经有了,别人写的差不多可以看懂了。下面大概记一下基本的正则元字符的意思,以后做复习和查找之用。

表1.常用的元字符
代码 说明
. 匹配除换行符以外的任意字符
/w 匹配字母或数字或下划线或汉字
/s 匹配任意的空白符
/d 匹配数字
/b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束


表2.常用的限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
 


例子: 1.要找的是hi后面不远处跟着一个Lucy,你应该用/bhi/b.*/bLucy/b /b并不匹配这些单词分隔符中的任何一个,它只匹配一个位置 .就是匹配除换行任何字符,*出现重复零次或更多次。

           2.要查找hi就更容易了/bhi/b

           3.0/d{2}-/d{8}的意思是0 这里/d后面的{2}({8})的意思是前面/d必须连续重复匹配2次(8次)。

           4./b/w{6}/b 匹配刚好6个字母/数字的单词

           5.^/d{5,12}$匹配5到12个数字。

           6./(?0/d{2}[) -]?/d{8}这个很好例子看懂就说明前面掌握的差不多了

转义:如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没法指定它们,因为它们会被解释成其它的意思。这时你就必须使用/来取消这些字符的特殊意义。因此,你应该使用/.和/*。当然,要查找/本身,你也得用//.

反义: 表3.常用的反义代码 代码/语法 说明
/W 匹配任意不是字母,数字,下划线,汉字的字符
/S 匹配任意不是空白符的字符
/D 匹配任意非数字的字符
/B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符


例如:

       1./S+匹配不包含空白符的字符串。

       2.<a[^>]+>匹配用尖括号括起来的以a开头的字符串。

替换:具体方法是用|把不同的规则分隔开

/(0/d{2}/)[- ]?/d{8}|0/d{2}[- ]?/d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用替换|把这个表达式扩展成也支持4位区号的。

后向引用:规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

/1代表分组1匹配的文本 /b(/w+)/b/s+/1/b可以用来匹配重复的单词,像go go, kitty kitty。首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(/b(/w+)/b),然后是1个或几个空白符(/s+),最后是前面匹配的那个单词(/1)。

例如:
1./b(/w+)/b/s+/1/b可以用来匹配重复的单词,像go go, kitty kitty

2./b(?<Word>/w+)/b/s+/k<Word>/b。请使用这样的语法:(?<Word>/w+)(或者把尖括号换成’也行:(?’Word’/w+)),这样就把/w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用/k<Word>

表4.分组语法 捕获
(exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置


(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如/b/w+(?=ing/b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I’m singing while you’re dancing.时,它会匹配sing和danc。

(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=/bre)/w+/b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=/d)/d{3})*/b,用它对1234567890进行查找时结果是234567890。

就这样已经入门了

下面是一个把xml文里面的数字节点转换成字符节点如下

  1.  String str = "<?xml version=/"1.0/" encoding=/"GB2312/"?>"  
  2.  + "<esb>"  
  3.  + "<route>"  
  4.   +"<from>"123"</from>"        // 确认消息中,to/from 与接收信息刚好相反   
  5.   +"<to>"123"</to>"  
  6.   +"<type>"+231"</type>"  
  7.   +"<area>"123"</area>"  
  8.  + "</route>"  
  9.  + "<public>"  
  10.   +"<ds_msg>"  
  11.    +"<time>"123"</time>"  
  12.    +"<ds_msg_id>"456"</ds_msg_id> "  
  13.    +"<ds_msg_class>"+"<13/>"+"</ds_msg_class>"  
  14.   +"</ds_msg>"  
  15.  + "</public>"  
  16.  +""  
  17.     
  18. "</esb>".replaceAll("<[//]?[0-9]+[//]?>""<java1/>");   
  19.       String regex="(</?)(//d+)(/?>)";   
  20.       String result=str.replaceAll(regex,"$1v$2$3");