[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]
RE: Got a program that generates a list of assertions about an XSD?
- From: "Costello, Roger L." <costello@mitre.org>
- To: "xml-dev@lists.xml.org" <xml-dev@lists.xml.org>
- Date: Sat, 14 Nov 2015 18:07:37 +0000
Hi Folks,
So, today I spent a few minutes writing an XSLT program that turns an XML Schema into a list of simple assertions.
For this XML Schema:
-------------------------------------------------------------
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.books.org"
xmlns="http://www.books.org"
elementFormDefault="qualified">
<xs:element name="BookStore">
<xs:complexType>
<xs:sequence>
<xs:element name="Book" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Author" type="xs:string"/>
<xs:element name="Date" type="xs:gYear"/>
<xs:element name="ISBN" type="xs:string"/>
<xs:element name="Publisher" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
-------------------------------------------------------------
my XSLT program generates this list of assertions:
(BookStore file Book-Store.xsd)
(BookStore kind element)
(BookStore targetNamespace "http://www.books.org")
(BookStore type complexType)
(BookStore minOccurs 1)
(BookStore maxOccurs 1)
(BookStore default none)
(BookStore fixed none)
(BookStore parent schema)
(BookStore location /schema/element[BookStore])
(Book file Book-Store.xsd)
(Book kind element)
(Book targetNamespace "http://www.books.org")
(Book type complexType)
(Book minOccurs 1)
(Book maxOccurs unbounded)
(Book default none)
(Book fixed none)
(Book parent BookStore)
(Book location /schema/element[BookStore]/complexType/sequence/element[Book])
(Title file Book-Store.xsd)
(Title kind element)
(Title targetNamespace "http://www.books.org")
(Title type string)
(Title minOccurs 1)
(Title maxOccurs 1)
(Title default none)
(Title fixed none)
(Title parent Book)
(Title location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Title])
(Author file Book-Store.xsd)
(Author kind element)
(Author targetNamespace "http://www.books.org")
(Author type string)
(Author minOccurs 1)
(Author maxOccurs 1)
(Author default none)
(Author fixed none)
(Author parent Book)
(Author location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Author])
(Date file Book-Store.xsd)
(Date kind element)
(Date targetNamespace "http://www.books.org")
(Date type gYear)
(Date minOccurs 1)
(Date maxOccurs 1)
(Date default none)
(Date fixed none)
(Date parent Book)
(Date location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Date])
(ISBN file Book-Store.xsd)
(ISBN kind element)
(ISBN targetNamespace "http://www.books.org")
(ISBN type string)
(ISBN minOccurs 1)
(ISBN maxOccurs 1)
(ISBN default none)
(ISBN fixed none)
(ISBN parent Book)
(ISBN location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[ISBN])
(Publisher file Book-Store.xsd)
(Publisher kind element)
(Publisher targetNamespace "http://www.books.org")
(Publisher type string)
(Publisher minOccurs 1)
(Publisher maxOccurs 1)
(Publisher default none)
(Publisher fixed none)
(Publisher parent Book)
(Publisher location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Publisher])
Then I used a pattern matcher (expressed in Common Lisp) to search the list of assertions for answers to questions:
-------------------------------------------------------
Question: What items have type string?
Query: (fetch '(? type string))
Results: ((TITLE TYPE STRING)
(AUTHOR TYPE STRING)
(ISBN TYPE STRING)
(PUBLISHER TYPE STRING))
-------------------------------------------------------
Question: What are the children of Book?
Query: (mapcar #'first (fetch '(? parent Book)))
Answer: (TITLE AUTHOR DATE ISBN PUBLISHER)
-------------------------------------------------------
Question: What elements have unbounded occurrences?
Query: (fetch '(? maxOccurs unbounded))
Answer: ((BOOK MAXOCCURS UNBOUNDED))
-------------------------------------------------------
Question: What are the potential root elements?
Query: (mapcar #'first (fetch '(? parent schema)))
Answer: (BOOKSTORE)
-------------------------------------------------------
Those are probing the schema with simple questions and queries, but the kinds of questions and queries that are possible are limited only by one's imagination.
This is pretty cool: using simple assertions about a schema to get answers to complex questions.
I think that "list of assertions" might be a useful common intermediate format for both XML Schema and JSON Schema. Your thoughts on this?
Below is the XSLT program that I wrote to generate the list of assertions, followed by the Common Lisp pattern matcher program that I wrote.
--------------------------------------------------------------
XSLT Program to Generate a List of Assertions
--------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="functions"
exclude-result-prefixes="xs f"
version="2.0">
<xsl:output method="text" />
<xsl:variable name="tns" select="/xs:schema/@targetNamespace"/>
<xsl:template match="/">
<xsl:text>(setf database
'(</xsl:text>
<xsl:for-each select="//xs:element[@name]">
<xsl:apply-templates select="." />
<xsl:text>
</xsl:text>
</xsl:for-each>
<xsl:text>))</xsl:text>
</xsl:template>
<xsl:template match="xs:element[@name]">
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> file Book-Store.xsd)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> kind element)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> targetNamespace "</xsl:text><xsl:value-of select="$tns"/><xsl:text>")</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> type </xsl:text><xsl:value-of select="f:my-type(.)"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> minOccurs </xsl:text><xsl:value-of select="if (not (@minOccurs)) then 1 else @minOccurs"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> maxOccurs </xsl:text><xsl:value-of select="if (not (@maxOccurs)) then 1 else @maxOccurs"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> default </xsl:text><xsl:value-of select="if (not (@default)) then 'none' else @default"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> fixed </xsl:text><xsl:value-of select="if (not (@fixed)) then 'none' else @fixes"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> parent </xsl:text><xsl:value-of select="f:my-parent(.)"/><xsl:text>)</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>(</xsl:text><xsl:value-of select="@name"/><xsl:text> location </xsl:text><xsl:value-of select="f:XPath-to-item(.)"/><xsl:text>)</xsl:text>
</xsl:template>
<xsl:function name="f:my-type">
<xsl:param name="element" />
<xsl:choose>
<xsl:when test="$element[@type]"><xsl:value-of select="if (contains($element/@type, ':')) then substring-after($element/@type, ':') else $element/@type" /></xsl:when>
<xsl:when test="$element[child::xs:complexType]"><xsl:text>complexType</xsl:text></xsl:when>
<xsl:when test="$element[child::xs:simpleType]"><xsl:text>simpleType</xsl:text></xsl:when>
</xsl:choose>
</xsl:function>
<xsl:function name="f:my-parent">
<xsl:param name="element" />
<xsl:value-of select="f:my-parent-aux($element/..)"/>
</xsl:function>
<xsl:function name="f:my-parent-aux">
<xsl:param name="node" />
<xsl:choose>
<xsl:when test="$node[self::xs:element[@name]]"><xsl:value-of select="$node/@name" /></xsl:when>
<xsl:when test="$node[self::xs:complexType[@name]]"><xsl:value-of select="$node/@name" /></xsl:when>
<xsl:when test="$node[self::xs:schema]">schema</xsl:when>
<xsl:otherwise><xsl:value-of select="f:my-parent-aux($node/..)"/></xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:function name="f:XPath-to-item">
<xsl:param name="item" as="element()" />
<xsl:for-each select="$item/ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:variable name="name" select="local-name()"/>
<xsl:choose>
<xsl:when test="@name">
<xsl:text>[</xsl:text><xsl:value-of select="@name"/><xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="@ref">
<xsl:text>[</xsl:text><xsl:value-of select="@ref"/><xsl:text>]</xsl:text>
</xsl:when>
<xsl:when test="count(preceding-sibling::*[local-name() = $name]) > 0">
<xsl:text>[</xsl:text><xsl:value-of select="count(preceding-sibling::*[local-name() = $name]) + 1"/><xsl:text>]</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:function>
</xsl:stylesheet>
--------------------------------------------------------------
Common Lisp Pattern Matcher Program
--------------------------------------------------------------
(setf database
'((BookStore file Book-Store-v1.xsd)
(BookStore kind element)
(BookStore targetNamespace "http://www.books.org")
(BookStore type complexType)
(BookStore minOccurs 1)
(BookStore maxOccurs 1)
(BookStore default none)
(BookStore fixed none)
(BookStore parent schema)
(BookStore location /schema/element[BookStore])
(Book file Book-Store-v1.xsd)
(Book kind element)
(Book targetNamespace "http://www.books.org")
(Book type complexType)
(Book minOccurs 1)
(Book maxOccurs unbounded)
(Book default none)
(Book fixed none)
(Book parent BookStore)
(Book location /schema/element[BookStore]/complexType/sequence/element[Book])
(Title file Book-Store-v1.xsd)
(Title kind element)
(Title targetNamespace "http://www.books.org")
(Title type string)
(Title minOccurs 1)
(Title maxOccurs 1)
(Title default none)
(Title fixed none)
(Title parent Book)
(Title location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Title])
(Author file Book-Store-v1.xsd)
(Author kind element)
(Author targetNamespace "http://www.books.org")
(Author type string)
(Author minOccurs 1)
(Author maxOccurs 1)
(Author default none)
(Author fixed none)
(Author parent Book)
(Author location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Author])
(Date file Book-Store-v1.xsd)
(Date kind element)
(Date targetNamespace "http://www.books.org")
(Date type gYear)
(Date minOccurs 1)
(Date maxOccurs 1)
(Date default none)
(Date fixed none)
(Date parent Book)
(Date location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Date])
(ISBN file Book-Store-v1.xsd)
(ISBN kind element)
(ISBN targetNamespace "http://www.books.org")
(ISBN type string)
(ISBN minOccurs 1)
(ISBN maxOccurs 1)
(ISBN default none)
(ISBN fixed none)
(ISBN parent Book)
(ISBN location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[ISBN])
(Publisher file Book-Store-v1.xsd)
(Publisher kind element)
(Publisher targetNamespace "http://www.books.org")
(Publisher type string)
(Publisher minOccurs 1)
(Publisher maxOccurs 1)
(Publisher default none)
(Publisher fixed none)
(Publisher parent Book)
(Publisher location /schema/element[BookStore]/complexType/sequence/element[Book]/complexType/sequence/element[Publisher])
))
(defun match-element (symbol1 symbol2)
(cond ((equal symbol1 symbol2) t)
((equal symbol2 '?) t)
(t nil)))
(defun match-triple (assertion pattern)
(and (= (length assertion) (length pattern))
(= (length assertion) 3)
(match-element (first assertion) (first pattern))
(match-element (second assertion) (second pattern))
(match-element (third assertion) (third pattern))))
(defun fetch (pattern)
(remove nil (mapcar #'(lambda (assertion) (if (match-triple assertion pattern) assertion)) database)))
[Date Prev]
| [Thread Prev]
| [Thread Next]
| [Date Next]
--
[Date Index]
| [Thread Index]