基于 XSD 模式和 Schematron 规则的 XML 校验插件的介绍和实现,第 2 部分

来源:developerWorks 中国 作者:陈 序明
  
本系列由上下两篇组成,第 1 篇从用户易用性角度上分析目前很多的开发框架、软件产品易用性方面存在的问题, 然后从易用性角度提出”基于 XSD 模式和 Schematron 规则的 XML 校验插件”,第 2 篇介绍该插件的使用方法,设计架构,使用的各种技术标准以及用户如何对其进行扩展。

设计架构

下图是整个验证框架的设计架构。整个框架是建立在 Eclipse WTP Validation 框架的基础上,提供了四类不同层次的校验:XML 验证、 XSD 模式验证、 Schematron 规则验证和类引用验证。

验证框架的输入为各种 XML 配置文件,用户可以基于 Eclipse XML 编辑器对这些 XML 配置文件进行编辑,当验证框架对这些 XML 配置文件进行验证后,输出为验证报告,其中包含验证过程中发现的所有错误和警告。这些错误和警告消息中包含了错误的具体文件、路径、位置(行、列),错误程度等。这些错误、警告列表将在问题属性列表 (Problem Properties List) 中进行显示,并在XML编辑器中相应错误位置标志出错误。接下来的章节中,将会对整个框架涉及到的技术和使用方法做详细的介绍。

图 1. 设计架构图


图 1. 设计架构图
设计架构图




Eclipse WTP(Web Tools Platform) 验证框架

WTP(Web Tools Platform) 验证框架介绍

WTP Validation 校验框架提供了一个可扩展的框架,基于这个框架可以定制开发对工作区间中资源进行验证的验证工具。这些资源可以是一个 Eclipse Resource (IResource),也可以是一个 EMF Resource(EObject) 。该框架提供了一系列的接口和API来控制对工作区间中的资源进行什么类型的校验,什么时候进行校验,如何进行校验。该框架支持下面的一些特性:

  1. 只对特定项目类型的项目中的资源进行校验,在扩展点中通过 project nature 属性来定制该 Validator 可以运行的项目性质
  2. 所有的定制的 Validator 都可以在两个层次上进行“开/关“。这里的“开/关”指是否可以运行该 Validator 。这两个层次分别是全局层次和项目层次。全局层次通过 Window -> Preferences -> Validation 进行配置,项目层次通过 IProject -> Properties -> Validation 进行配置
  3. 过滤校验的文件类型,扩展点中可以配置该 Validator 只对指定的文件类型进行校验。
  4. 支持手工触发资源的校验, WTP Validation 校验框架支持通过右键菜单,对一些选中的资源进行校验工作。
  5. 支持增量式验证方式,即工作区间自动编译的时候,会自动校验工作区间中的允许被校验的资源。
  6. WTP Validation 校验框架支持扩展的 Validation Marker 类型。

代码列表 1. org.eclipse.wst.validation.validator 扩展点的一个例子
   <extension
         id="XMLValidator"
         name="XML Validator"
         point="org.eclipse.wst.validation.validator">
      <validator>
         <projectNature
               id="org.eclipse.jdt.core.javanature">
         </projectNature>  
         <filter
               objectClass="org.eclipse.core.resources.IFile"
               nameFilter="*.test">
         </filter>                                  
         <run
               enabled="true"
               async="true"
               fullBuild="true"
         	   incremental="true"
               class="com.ibm.xml.validator.XMLValidator">
         </run>
         <helper
               class="com.ibm.xml.validator.XMLValidatorHelper">
         </helper>
      </validator>
   </extension>

 

扩展这个扩展点能够实现一个新的 WTP Validator, 扩展 Validator 需要定义项目性质 (Project Nature) ,用户也可以配置过滤器以让 Validator 只验证符合一定过滤条件的配置文件,新扩展的 Validator 可以设置是否是手工出发的验证还是增量的自动验证,同时还需要设置执行验证逻辑的 Java 类,和辅助的 Helper Java 类。关于这个扩展点具体信息,可以参考 eclipse 扩展点文档。

几个重要接口和 API

  1. IValidator

要实现新的 Validator,必须扩展并实现这个接口,通过这个接口的实现验证资源模型。Validator 通过一个 IHelper 实现类来装载被验证的资源模型,然后在校验逻辑中遍历整个资源模型,如果发现有错误或警告,通过 IReporter 实现类进行报告,最后呈现给用户。

  1. IReporter

IReporter 接口的作用是实现用户交互性。IReporter 能够显示校验消息,删除校验消息,显示子消息等。每一个 Validator 都使用一个 IReporter 的实现,但是一个 IReporter 实现类可以被多个 IValidator 实现类实用。

  1. IHelper

IHelper 接口为 IValidator 提供装载资源机制,这个接口提供了方法辅助IValidator 装载和初始化特殊的资源模型。这里的资源模型指任何类别的被验证的对象。

  1. IMessage

IMessage 用户表示一个支持国际化的验证消息。如果一个 Validator 运行在一台服务器上,并且客户端的 Locale 和服务器不同,那校验信息最终会被转换成客户端的 Locale,再呈现给客户。IMessage 作为错误消息在 IValidator 中被传给IReporter,并最终在 IReporter 中进行解析和显示。

集成 XSD 校验和 Schematron 校验

下面一段代码是在 XMLValidator 类的 validateFile 方法中,该方法执行所有的校验逻辑,并与 WTP Validation 框架结合,在 Eclipse 平台显示校验结果。对 XML 配置文件校验过程中,首先进行 XSD 模式校验,其次进行 Schematron 规则校验,校验的每一个错误结果都对应一个 Message 对象,并存在 vReporter 的列表中,最后在统一进行显示、标记。


代码列表 2. XMLValidator 类的 validateFile 方法片断
//对 XML配 置 文 件 进 行 XSD 模 式 校 验 
SchemaValidator schemaValidator = new SchemaValidator(file);
	InputStream steam = new ByteArrayInputStream(xmlModel
	       .getStructuredDocument().get().getBytes("UTF-8"));
schemaValidator.validate(steam, vReporter, this);

//对 XML 配置文件进行 Schematron规则校验 
InputStream steam1 = new ByteArrayInputStream(xmlModel
                .getStructuredDocument().get().getBytes("UTF-8"));
SchematronValidator schValidator = new SchematronValidator(file);
			schValidator.validate(steam1, vReporter, this);
List messages = vReporter.list;

//清除原来老的标记 
clearMarkers(file, this, reporter);

//显示、定位 XSD 模式校验和 Schematron 规则校验的错误信息
updateValidationMessages(file, messages, document, reporter);


图 2. 校验过程的序列图如下





基于 XSD 的验证

XSD 模式校验的实现

这里利用 SAX 对 XSD 进行验证,其 ErrorHandler 为 XMLSchemaErrorHandler 类。所有的 XML 和 XSD 模式校验错误都会在 XMLSchemaErrorHandler 被捕获,并且创建 WTP Message 对象,最终报告给 WTP Validation 框架,并进行显示、定位。


代码列表 3. SchemaValidator 类中的核心方法 validate 方法
public void validate(InputStream steam, IReporter reporter, IValidator validator)
{
try
{
XMLValidationInfo validationInfo = new XMLValidationInfo();
StandardParserConfiguration configuration = 
                              new MyStandardParserConfiguration(validationInfo);
       XMLReader parser = new org.apache.xerces.parsers.SAXParser(configuration);

//设置sax parser参数
parser.setFeature("http://xml.org/sax/features/validation", true);
parser.setFeature("http://apache.org/xml/features/validation/schema", true);
parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
parser.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);

//设置XSD模式文件路径
       Setting setting = Setting.getInstance();
parser.setProperty(
"http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", 
                                setting.getXSDFile(file));


//设置sax parser的错误处理类
 parser.setErrorHandler(new XMLSchemaErrorHandler(file, 
                                 reporter, validator, validationInfo));
         parser.parse(new InputSource(steam)); 
        }
catch ( SAXException e )
{
    System.out.print(e.getMessage());
}
catch ( IOException e )
{
    e.printStackTrace();
} 
}


代码列表 4. XMLSchemaErrorHandler 中的错误处理函数
public void error(SAXParseException exception) throws SAXException
{
//创建WTP Message对象,并根据错误信息进行初始化
LocalizedMessage message;
 message = new LocalizedMessage(IMessage.HIGH_SEVERITY,
                                 exception.getLocalizedMessage(), uri);
message.setLineNo(exception.getLineNumber()); 
_validationInfo.setColumn(exception.getColumnNumber());
        addInfoToMessage(_validationInfo, message);

//报告该WTP Message对象
    _reporter.addMessage(_validator, message);
}

如何使用

要对 XML 配置文件进行 XSD 模式验证,首先必须提供该 XSD 模式文件。附件中插件中的 com.ibm.xml.validator->xsd->type.xsd 文件既是 IBM BTT5.2(Branch Transformation Toolkit ) 配置文件中的其中一个 XSD 模式文件。我们关联该 XSD 模式文件,就可以利用该文件对 XML 配置文件进行校验。例子中为了简单只支持在 com.ibm.xml.validator.Setting 类中进行配置该 XSD 路径,当然我们也可以实现在一个 XML 配置文件或者 Properties 配置文件中进行配置。





基于Schematron 的验证

Schematron 标准的实现

Schematron 作为 ISO 标准,有很多相应的实现,比如:基于 XSLT 的 ISO Schematron 参考实现 (The "Reference" Implementation of ISO Schematron),Sun MSV(Multi-Schema Validators) Schematron Add-on 等。作者研究了 ISO Schematron 标准( ISO/IEC 19757-3:2006),提供了一个 Schematron 的子集实现,该自己实现支持基本的 Schematron 规则定义、解析、错误报告功能。这个实现基于 XSLT,下面是相应的 XSLT 代码:


代码列表 5. ISO Schematron 标准的 XSLT 代码
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
	xmlns:sch="http://www.ibm.com.cn/XML/schematron"
	xmlns:xml-validation="http://www.w3.org/1999/XSL/TransformAlias"> 
	
<xsl:namespace-alias stylesheet-prefix="xml-validation" result-prefix="xsl"/>
<xsl:output method="xml"/> 

<xsl:template match="sch:schema | schema">
<xml-validation:stylesheet version="1.0">   
<xsl:apply-templates mode="sch-keyword" select="sch:pattern/sch:rule | pattern/rule "/> 
      <xml-validation:template match="/">
         <xsl:apply-templates mode="validate-patterns"/> 
      </xml-validation:template> 
      
      <xml-validation:template match="*" mode="error-element-full-path">
         <xml-validation:apply-templates select="parent::*"
      mode="error-element-full-path"/>
         <xml-validation:text>/</xml-validation:text> 
  		 <xml-validation:value-of select="name()"/> 
         <xml-validation:text>[</xml-validation:text>
         <xml-validation:value-of
      select="1+count(preceding-sibling::*[name()=name(current())])"/>
         <xml-validation:text>]</xml-validation:text>
      </xml-validation:template>
      <xsl:apply-templates/> 
   </xml-validation:stylesheet>
</xsl:template>

<xsl:template match="sch:pattern | pattern" mode="validate-patterns">  
<xml-validation:apply-templates select="/" mode="Pattern{count(preceding-sibling::*)}"/>
</xsl:template> 

<xsl:template match="sch:assert | assert">
   <xsl:if test="not(@test)">
      <xsl:message>xml Assert Error: no test attribute</xsl:message>
   </xsl:if> 
   <xml-validation:choose>
      <xml-validation:when test="{@test}"/>
      <xml-validation:otherwise> 
         <xsl:call-template name="report-error" />
      </xml-validation:otherwise>
   </xml-validation:choose> 
</xsl:template> 

<xsl:template match="sch:pattern | pattern">
      <xsl:apply-templates/> 
      <xml-validation:template match="text()" priority="-1" 
   mode="Pattern{count(preceding-sibling::*)}"> 
      </xml-validation:template> 
</xsl:template> 
 
<xsl:template match="sch:rule | rule">
   <xsl:if test="not(@context)">
      <xsl:message>XML Rule Error: no context attribute</xsl:message>
   </xsl:if>
   <xml-validation:template match="{@context}" 
priority="{count(following-sibling::*)}" 
mode="Pattern{count(../preceding-sibling::*)}"> 
      <xsl:apply-templates/>
 <xml-validation:apply-templates mode="Pattern{count(../preceding-sibling::*)}"/>
   </xml-validation:template>
</xsl:template> 

<xsl:template match="text()" priority="-1" mode="sch-keyword" />  
 
<xsl:template name="report-error"> 
	<xsl:text>XML Rule Assert fails: XMLErrorXMLMessage"</xsl:text>
	<xsl:value-of select="normalize-space(.)"/>"XMLMessageXMLXPATH
	    <xml-validation:apply-templates mode="error-element-full-path" 
	                  select="." />XMLXPATHXMLError
</xsl:template>
</xsl:stylesheet>

为了支持与 Eclipse WTP 验证框架集成,作者的这个 Schematron 参考实现对错误消息进行了预先设定,这些错误消息解析过程中会被本框架的解析引擎所捕获,并根据我们预先设定的规则进行解析,最后生成相应的错误报告。定制规则如下:

  1. 两个 XMLError 之间的内容组成一个 schematron 规则验证错误。XML 配置文件的所有 Schematron 验证错误将会做为一个字符串形式返回给解析引擎,其中每两个 XMLError 之间包含了一个验证错误。
  2. XMLError 中包含的验证错误字符串中,两个 XMLMessage 之间的字符串是该错误的错误消息。这些错误消息是用户定义 schematron 配置文件的时候书写的,错误消息最终会被显示到问题属性视图(Problem Properties View) 中,呈现给用户。
  3. XMLError 中包含的验证错误字符串中,两个 XMLPath 之间的字符串是发生该错误的 XML 元素的 XPath 路径。要对错误进行定位,需要知道错误发生的行,列,发生错误的字符串等。这些信息都可以通过该错误 XML 元素的 XPath 路径来得到。

Schematron 规则解析引擎的实现:

我们上面提到过,本文的”基于 XSD 模式和 Schematron 规则的 XML 校验插件”的 Schematron 规则解析采用基于 XSLT 的实现. SchtrnValidator 类中的下面方法包装了具体的实现,具体请参考代码:

代码列表 6. SchtrnValidator 中的 validateXMLBySchtron 方法

public static String validateXMLBySchtron(StreamSource xml, String xmlPath, String schema)

上面的对 XML 配置文件的 Schematron 规则校验,将返回字符串,其中包含了所有的错误信息,错误信息格式如上一小节的扩展的预定义格式所示.之后对返回的错误信息集的字符串进行解析,并生成一系列的 SchematronErrorMessage 对象,最终根据该对象生成相应的 WTP Message 对象,进行错误显示、定位。具体的实现细节请参考附件中的例子。

如何使用

要对 XML 配置文件进行 Schematron 规则校验,首先必须提供该 Schematron 规则定义文件。附件中插件中的 com.ibm.xml.validator->sch->type.sch 文件既是IBM BTT5.2(Branch Transformation Toolkit ) 配置文件中的其中一个 Schematron 规则文件。我们关联该 Schematron 规则定义文件,系统就可以自动地利用该文件对 XML 配置文件进行校验。例子中为了简单只支持在 com.ibm.xml.validator.Setting 类中进行配置该 XSD 路径,当然我们也可以实现在一个 XML 配置文件或者 Properties 配置文件中进行配置。


代码列表 7. type.sch 文件中的其中一条 Schematron rule
<sch:pattern name="reference & duplicated id.">
 <sch:rule context="//*">
 <sch:assert test="not(@refType) 
            or /child::*/type[@id=current()/@refType]">
	   The 'refType' doesn't exist.ATTRIBUTErefTypeATTRIBUTE
	        </sch:assert> 
        </sch:rule>	
</sch:pattern>

该 rule 验证所有 XML 元素的 ”refType” 属性必须引用到一个已经存在的 <type>…</type> 元素。否则,就会报校验错误,其中错误消息为:The 'refType' doesn't exist。”ATTRIBUTErefTypeATTRIBUTE” 表示错误发生的属性是 refTy.这个对 Schematron 的预定扩展在 ”Schematron 规则解析引擎” 中将被用于定位错误。





类路径 (Classpath) 验证

类路径 (Classpath) 验证的实现

类路径验证的实现包括两个部分:

  1. 抽取类路径字符串,抽取类路径字符串采用上节介绍的 Schematron 规则,下面是 type.sch 中定义的抽取类路径字符串的 Schematron 规则:

代码列表 8. type.sch 中定义的抽取类路径字符串的 Schematron 规则
<sch:pattern name="Validate dataName Reference.">
  <sch:rule context="type">
	<sch:assert test="not(@implClass)">
	The class cannot be resolved.ATTRIBUTEREFimplClassREFATTRIBUTE
	</sch:assert>
   </sch:rule>		
 </sch:pattern>

该规则采用了对 Schematron 的预定扩展,其中 ATTRIBUTEREFimplClassREFATTRIBUTE 表示 ATTRIBUTEREF 中间的 implClass 是类路径字符串。

  1. 验证该字符串是否为合法类路径,

从 XML 配置文件中抽取出类路径字符串后,利用Eclipse JDT 对该类路径字符串进行验证。核心验证代码如下所示:


代码列表 9. 利用 Eclipse JDT 对该类路径字符串进行验证
/**
 * 验证 import类路径字符串是否在 project 项目的 classpath 中
*  @param project, 需要验证配置文件所在的项目
 * @param imports, import 的类路径字符串
 * @return, 如果 import 字符串正确则返回 null,否则返回出错的路径
*/
public String validate(IProject project, char[][] imports) {
String result = null;
IJavaProject javaProject = JavaCore.create(project);
if (javaProject == null) {
return null;
}
else 
{
NameEnvironment nameEnviroment = new NameEnvironment(javaProject);

for (int i = 0; i < imports.length; i++) {
char[] importDeclaration = imports[i];
char[][] splitDeclaration = CharOperation.splitOn('.',
	importDeclaration);
int splitLength = splitDeclaration.length;
if (splitLength > 0) 
{
	char[] pkgName = splitDeclaration[splitLength - 1];
	if (pkgName.length == 1 && pkgName[0] == '*') 
{
  char[][] parentName;
  switch (splitLength) 
{
  case 1:
	parentName = null;
	break;
	case 2:
	parentName = null;
	pkgName = splitDeclaration[splitLength - 2];
	break;
	default:
	 parentName =CharOperation.subarray(splitDeclaration, 0, splitLength - 2);
	 pkgName = splitDeclaration[splitLength - 2];
	
}
	if (!nameEnviroment.isPackage(parentName, pkgName)) 
{
	 result = new String(importDeclaration); 
	}
	} else 
{
	if (nameEnviroment.findType(splitDeclaration) == null) 
{
		result = new String(importDeclaration);
		}
	}
} else 
{
	result = new String(importDeclaration);
}
}
}
return result;
} 

如何使用

要对 XML 配置文件进行类路径校验,必须提供该 Schematron 规则定义。上面提到过的 type.sch 文件中的一条 Schematron rule:


代码列表 10. type.sch 文件中的一条 Schematron rule
<sch:pattern name="Validate dataName Reference.">
  <sch:rule context="type">
	<sch:assert test="not(@implClass)">
	The class cannot be resolved.ATTRIBUTEREFimplClassREFATTRIBUTE
	</sch:assert>
   </sch:rule>	
 </sch:pattern>

该 rule 验证 <type>…</type> XML 元素中的 ”implClass” 属性的值代表的类路径是否是在该配置文件所在项目的 CLASSPATH 中。否则,就会报校验错误,其中错误消息为:The class cannot be resolved。





如何运行例子

  1. 下载附件中的插件
  2. 解压并导入包含 WTP 的 Eclipse3.2 中
  3. 运行该插件,并在运行 workbench 中建立一java工程,把 com.ibm.xml.validator->sample->dsetype.xml 文件拷贝到这个工程下
  4. 在Window -> Preferences -> Validation 中,配置 Developerwork XML Validator 使其 Manual 和 Build 对话框都选上,然后确定
  5. 在java 工程中,右键盘选中 dsetype.xml 文件,选择 Validation 菜单
  6. 查看错误




小结

这一篇文章介绍了”基于XSD模式和Schematron规则的XML校验插件”的使用方法,设计架构,使用的各种技术标准以及用户如何对其进行扩展。(责任编辑:A6)


时间:2008-10-24 15:15 来源:developerWorks 中国 作者:陈 序明 原文链接

好文,顶一下
(2)
100%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量