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))) _______________________________________________________________________ XML-DEV is a publicly archived, unmoderated list hosted by OASIS to support XML implementation and development. To minimize spam in the archives, you must subscribe before posting. [Un]Subscribe/change address: http://www.oasis-open.org/mlmanage/ Or unsubscribe: xml-dev-unsubscribe@lists.xml.org subscribe: xml-dev-subscribe@lists.xml.org List archive: http://lists.xml.org/archives/xml-dev/ List Guidelines: http://www.oasis-open.org/maillists/guidelines.php