schematron
TRANSCRIPT
Schematron
Emiel Paasschens, AMIS - 7 december UKOUG
Business Load Balancing by Complex
Message Validation with the Oracle
SOA Suite
Agenda
• Early fault detection
• Current solution: XSD validation
• Validation Gap
• Schematron
• Schematron in SOA Suite
• Simple use case example
• Demo
Fault DetectionThe earlier the better!
• Reduces load
• Decreases monitor ‘pollution’ (logs, monitor screens)
• May even prevent system crashes
• Response earlier (back to customer)
• Lower costs
Early Fault Detection in SOA
SOA: Webservices, SOAP
Early fault detection: The 1st possibility is error detection in accepting the request message.
Validating the request message
Request message is XML (SOAP) XML Validation XSD (Schema)
Current solution: XSD validation
XML Schema (XSD):
Defines structure of XML including data type of elements and constraints.
1. StructureElement “Person” contains child element “Name” and “Birthdate” in this
order.
2. Data typeElement “Name” is of String type and element “Birthdate” is of type date.
3. ConstraintsElement “Name” is at least two characters long.
• XSD can be seen as the “ERD” or “DB Design” for XML documents
XSD Validation
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://amis.nl/schematrondemo/common"
targetNamespace="http://amis.nl/schematrondemo/common"
elementFormDefault="qualified">
<xsd:element name="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Birthdate" type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Structure
XSD Validation
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://amis.nl/schematrondemo/common"
targetNamespace="http://amis.nl/schematrondemo/common"
elementFormDefault="qualified">
<xsd:element name="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Birthdate" type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Type
XSD Validation
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://amis.nl/schematrondemo/common"
targetNamespace="http://amis.nl/schematrondemo/common"
elementFormDefault="qualified">
<xsd:element name="Person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Birthdate" type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Constraints
Validation Gap
Three types of XML Business Rule Validation:
1. On data / element itself:Data type and (data) constraints XSD (Even complex data constraints with regular expressions)
2. XML structure:Element names & Hierarchy (child-parent) constraintsXSD? Partial! Optional combinations are difficult (choice combinations) or even impossible.
3. Constraints between elements Typically more Business Rules validations e.g. sum of all percentage attributes in the XML document must be 100.??
Schematron
• Used for validating an XML Document
• Validation of (conditional) structure
• Validation between nodes (elements/attributes), Business Rules
• Rules are defined in Schematron format which is ‘just’ an XML document
• Is built upon XPath expressions so no new language, only XML and XPath knowledge required!
• Specifies the error message (so you are in control of the output)
• Is an ISO/IEC Standard: 19757-3 (2006)
• Basically is a double XSTL transformation (under the hood)
Schematron
How does it work:
1. Define the validations with the usage of XPath expressions in an XML document in a fixed format and structure (according to the SchematronXSD).
2. Transform this validations XML with a specific Schematron XSLT into a new XSLT, which ‘contains/implements’ the validations of step 1.(In the SOA Suite this is done ,‘under the hood’, by the Runtime Engine)
3. This generated XSLT (containing the validations) can be used to validate XML data/payload by executing a transformation on it. (In the SOA Suite this is done ,‘under the hood’, by the Runtime Engine)
Any output are errors! (these error messages were also specified in step 1). So no output means the data is valid.
Schematron
Double XSLT transformation:
1. Rules.xml with Schematron.xslt Rules.xslt
2. Data.xml with Rules.xslt Result
Schematron XML
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.ascc.net/xml/schematron">
<pattern name="patternName">
<rule context="x-path">
<assert test="x-path condition">Error message</assert>
<report test="x-path condition">Error message</report>
...
</rule>
</pattern>
<pattern name="patternName">
...
</schema>
Schematron Example
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.ascc.net/xml/schematron">
<pattern name="Number of characters in an abbreviation">
<rule context="//Department">
<report test="string-length(@abb) < 2">There are not enough
characters in the abbreviation</report>
<report test="string-length(@abb) > 3">There are too much
characters in the abbreviation</report>
</rule>
</pattern>
</schema>
Just a name
Context: ‘starting point’ for the conditions
Error messagesConditions
Attribute “abb” of all “Department” elements must be 2 or 3 long.
Schematron Example
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.ascc.net/xml/schematron" >
<pattern name="Sum equals 100%.">
<rule context="//Total">
<assert test="sum(./Percent) = 100">Sum is not 100%.</assert>
</rule>
</pattern>
</schema>
The sum of all direct child elements “Percent” under element “Total” must be 100.
Schematron in the SOA Suite
• Default filename extension “sch”
• Only assert tag, no report tag!
assert=not(report)
• Define namespace prefixes with uri tag:<ns uri="http://amis.nl/schematrondemo/company" prefix="cmp" />
• Implemented in Mediator:
Use Case Example
Company HRM XML file:Company element contains departments which contains employees:
• An employee may not be the manager of himself.
• All normal employees (so not a manager) must have a manager.
• There is only one manager without a manager (so there is only one president).
• All employees should have less salary than any manager(manager = employee in department named “Managers”).
• The relation of manager and employee is a valid one. This means that the manager of an employee must exist.
Use Case Example
<Company><Department name="Ground One" abbr="GR1">...</Department>
<Department name="Ground Two" abbr="GR2">
<Employees>
<Employee id="13" manager_id="20">
<Name>P. Pietersen</Name>
<Salary>1550</Salary>
</Employee>
<Employee id="14" manager_id="20">
<Name>S. Smit</Name>
<Salary>1600</Salary>
</Employee>
</Employees>
</Department>
<Department name="Managers" abbr="MAN">
<Employees>
<Employee id="15">
<Name>M.A. Nager</Name>
<Salary>1700</Salary>
</Employee>
<Employee id="20" manager_id="25">
<Name>L.E. Ader</Name>
<Salary>1600</Salary>
Use Case Example
An employee may not be the manager of himself.
<pattern name="Employee may not be the manager of himself">
<rule context="//com:Employee[@manager_id]">
<assert test="@manager_id != @id">Employee may not manage himself</assert>
</rule>
</pattern>
Use Case Example
All normal employees (so not a manager) must have a manager.
<pattern name="All normal employees have a manager">
<rule context="//cmp:Department[@name!='Managers']/cmp:Employees/com:Employee">
<assert test="@manager_id">Employee must have a manager</assert>
</rule>
</pattern>
Use Case Example
There is only one manager without a manager (only one president).
<pattern name="Only one manager without manager, mr president">
<rule context="//cmp:Department[@name='Managers']/cmp:Employees">
<assert test="count(com:Employee[not(@manager_id)]) = 1">There should be
only one president</assert>
</rule>
</pattern>
Use Case Example
All employees should have less salary than any manager(manager = employee in department “Managers”).
<pattern name="Managers earn more than normal employees">
<rule
context="//cmp:Department[@name!='Managers']/cmp:Employees/com:Employee">
<assert test="com:Salary <
min(//cmp:Department[@name='Managers']/cmp:Employees/com:Employee/com:Salary)">
Employee earns too much</assert>
</rule>
</pattern>
Use Case Example
The relation manager and employee is a valid one, so the manager of an employee must exist.
Keep in mind that the president doesn’t have manager!
<pattern name="Manager does not exist">
<rule context="//com:Employee[@manager_id]">
<assert test=
"//cmp:Company/cmp:Department[@name='Managers']/cmp:Employees/com:Employee[@id=c
urrent()/@manager_id]">No valid manager</assert>
</rule>
</pattern>
Use Case Example
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.ascc.net/xml/schematron">
<ns uri="http://amis.nl/schematrondemo/company" prefix="cmp" />
<ns uri="http://amis.nl/schematrondemo/common" prefix="com" />
<pattern name="Managers earn more than normal employees">
<rule context= "//cmp:Department[@name!='Managers']/cmp:Employees/com:Employee">
<assert test="com:Salary <
min(//cmp:Department[@name='Managers']/cmp:Employees/com:Employee/com:Salary)">Employee
earns too much: <value-of select="com:Salary"/></assert>
</rule>
</pattern>
<pattern name="Employee may not be the manager of himself">
<rule context="//com:Employee[@manager_id]">
<assert test="@manager_id != @id">Employee may not manage himself</assert>
</rule>
</pattern>
<pattern name="All normal employees have a manager">
<rule context=
"//cmp:Company/cmp:Department[@name!='Managers']/cmp:Employees/com:Employee">
<assert test="@manager_id">Employee must have a manager</assert>
</rule>
</pattern>
<pattern name="Only one manager without manager, the president">
<rule context="//cmp:Company/cmp:Department[@name='Managers']/cmp:Employees">
<assert test="count(com:Employee[not(@manager_id)]) = 1">There should be only one
president</assert>
...