本系列由上下兩篇組成,第 1 篇從用戶易用性角度上分析目前很多的開發框架、軟體產品易用性方面存在的問題, 然後從易用性角度提出”基於 XSD 模式和 Schematron 規則的 XML 校驗插件”,第 2 篇介紹該插件的使用方法,設計架構,使用的各種技術標準以及用戶如何對其進行擴展。
設計架構
下圖是整個驗證框架的設計架構。整個框架是建立在 Eclipse WTP Validation 框架的基礎上,提供了四類不同層次的校驗:XML 驗證、 XSD 模式驗證、 Schematron 規則驗證和類引用驗證。
驗證框架的輸入為各種 XML 配置文件,用戶可以基於 Eclipse XML 編輯器對這些 XML 配置文件進行編輯,當驗證框架對這些 XML 配置文件進行驗證后,輸出為驗證報告,其中包含驗證過程中發現的所有錯誤和警告。這些錯誤和警告消息中包含了錯誤的具體文件、路徑、位置(行、列),錯誤程度等。這些錯誤、警告列表將在問題屬性列表 (Problem Properties List) 中進行顯示,並在XML編輯器中相應錯誤位置標誌出錯誤。接下來的章節中,將會對整個框架涉及到的技術和使用方法做詳細的介紹。
圖 1. 設計架構圖
Eclipse WTP(Web Tools Platform) 驗證框架
WTP(Web Tools Platform) 驗證框架介紹
WTP Validation 校驗框架提供了一個可擴展的框架,基於這個框架可以定製開發對工作區間中資源進行驗證的驗證工具。這些資源可以是一個 Eclipse Resource (IResource),也可以是一個 EMF Resource(EObject) 。該框架提供了一系列的介面和API來控制對工作區間中的資源進行什麼類型的校驗,什麼時候進行校驗,如何進行校驗。該框架支持下面的一些特性:
<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
要實現新的 Validator,必須擴展並實現這個介面,通過這個介面的實現驗證資源模型。Validator 通過一個 IHelper 實現類來裝載被驗證的資源模型,然後在校驗邏輯中遍歷整個資源模型,如果發現有錯誤或警告,通過 IReporter 實現類進行報告,最後呈現給用戶。
IReporter 介面的作用是實現用戶交互性。IReporter 能夠顯示校驗消息,刪除校驗消息,顯示子消息等。每一個 Validator 都使用一個 IReporter 的實現,但是一個 IReporter 實現類可以被多個 IValidator 實現類實用。
IHelper 介面為 IValidator 提供裝載資源機制,這個介面提供了方法輔助IValidator 裝載和初始化特殊的資源模型。這裡的資源模型指任何類別的被驗證的對象。
IMessage 用戶表示一個支持國際化的驗證消息。如果一個 Validator 運行在一台伺服器上,並且客戶端的 Locale 和伺服器不同,那校驗信息最終會被轉換成客戶端的 Locale,再呈現給客戶。IMessage 作為錯誤消息在 IValidator 中被傳給IReporter,並最終在 IReporter 中進行解析和顯示。
集成 XSD 校驗和 Schematron 校驗
下面一段代碼是在 XMLValidator 類的 validateFile 方法中,該方法執行所有的校驗邏輯,並與 WTP Validation 框架結合,在 Eclipse 平台顯示校驗結果。對 XML 配置文件校驗過程中,首先進行 XSD 模式校驗,其次進行 Schematron 規則校驗,校驗的每一個錯誤結果都對應一個 Message 對象,並存在 vReporter 的列表中,最後在統一進行顯示、標記。
//對 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); |
基於 XSD 的驗證
XSD 模式校驗的實現
這裡利用 SAX 對 XSD 進行驗證,其 ErrorHandler 為 XMLSchemaErrorHandler 類。所有的 XML 和 XSD 模式校驗錯誤都會在 XMLSchemaErrorHandler 被捕獲,並且創建 WTP Message 對象,最終報告給 WTP Validation 框架,並進行顯示、定位。
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(); } } |
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 代碼:
<?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 參考實現對錯誤消息進行了預先設定,這些錯誤消息解析過程中會被本框架的解析引擎所捕獲,並根據我們預先設定的規則進行解析,最後生成相應的錯誤報告。定製規則如下:
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 配置文件中進行配置。
<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) 驗證的實現
類路徑驗證的實現包括兩個部分:
<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 是類路徑字元串。
從 XML 配置文件中抽取出類路徑字元串后,利用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:
<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。
如何運行例子
小結
這一篇文章介紹了”基於XSD模式和Schematron規則的XML校驗插件”的使用方法,設計架構,使用的各種技術標準以及用戶如何對其進行擴展。(責任編輯:A6)
[火星人 ] 基於 XSD 模式和 Schematron 規則的 XML 校驗插件的介紹和實現,第 2 部分已經有1137次圍觀