So you have just created a new non-XMLsyntax for XML Schemas. Hooray! You have probably missed various features that are built into XSD, given how complex it is.
Instead of converting to your non-XML statements and using LISP pattern matching to extract information, why not just use XSLT or XQuery expressions to extract the same information? You would still have to write the appropriate pattern matching expressions, but you wouldn't also have to learn LISP and have LISP tools.
TomP
On 11/14/2015 11:07 AM, Costello, Roger L. wrote:
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
_______________________________________________________________________
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