I've made a first test XSL file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <xsl:output method="text"/> <xsl:template match="xsd:simpleType"> sub <xsl:value-of select="@name" /> { <xsl:for-each select="xsd:annotation/xsd:documentation"># <xsl:val +ue-of select="normalize-space(.)" /></xsl:for-each> my($class, $value) = @_; return FALSE if _is_null($value); return <xsl:for-each select="xsd:restriction"><xsl:value-of select +="replace(@base,':', '_')" />($value) and <xsl:apply-templates mode=" +restriction" select="*"/>TRUE;</xsl:for-each> } </xsl:template> <xsl:template mode="restriction" match="xsd:minInclusive">$value &gt;= + <xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:minExclusive">$value &gt; +<xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:maxInclusive">$value &lt;= + <xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:maxExclusive">$value &lt; +<xsl:value-of select="@value" /> and </xsl:template> </xsl:stylesheet>
It converts the sample from brian's root node, after I wrapped in it an "xsd:schema" top level element, just as in the XSD file he linked to, using Saxon8, into:
sub longitudeType { # The longitude of the point. Decimal degrees, WGS84 datum. my($class, $value) = @_; return FALSE if _is_null($value); return xsd_decimal($value) and $value >= -180.0 and $value < 180.0 + and TRUE; }
What do you think, brian? Is this close?

Here's the complete XML file:

<?xml version="1.0" encoding="utf-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.topografix.com/GPX/1/1" targetNamespace="http://www.topografix.com/GPX/1/1" elementFormDefault="qualified"> <xsd:simpleType name="longitudeType"> <xsd:annotation> <xsd:documentation> The longitude of the point. Decimal degrees, WGS84 datum. </xsd:documentation> </xsd:annotation> <xsd:restriction base="xsd:decimal"> <xsd:minInclusive value="-180.0"/> <xsd:maxExclusive value="180.0"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>

It doesn't work in XML Notepad, because of the replace (which replaces the colon with an underscore). Without it, it works in MS XML Notepad, too — except for the missing substitution, of course.

For kicks, I've processed the original XSD file this way, and (apart from some junk from those element that are now not handled in the XSD file) I get this:

sub latitudeType { # The latitude of the point. Decimal degrees, WGS84 datum. my($class, $value) = @_; return FALSE if _is_null($value); return xsd_decimal($value) and $value >= -90.0 and $value <= 90.0 +and TRUE; } sub longitudeType { # The longitude of the point. Decimal degrees, WGS84 datum. my($class, $value) = @_; return FALSE if _is_null($value); return xsd_decimal($value) and $value >= -180.0 and $value < 180.0 + and TRUE; } sub degreesType { # Used for bearing, heading, course. Units are decimal degrees, tr +ue (not magnetic). my($class, $value) = @_; return FALSE if _is_null($value); return xsd_decimal($value) and $value >= 0.0 and $value < 360.0 an +d TRUE; } sub fixType { # Type of GPS fix. none means GPS had no fix. To signify "the fix +info is unknown, leave out fixType entirely. pps = military signal us +ed my($class, $value) = @_; return FALSE if _is_null($value); return xsd_string($value) and TRUE; } sub dgpsStationType { # Represents a differential GPS station. my($class, $value) = @_; return FALSE if _is_null($value); return xsd_integer($value) and $value >= 0 and $value <= 1023 and +TRUE; }

This is fun.

p.s. I used TRUE and FALSE as booleans for readability. You can always replace them with 1 and 0, but I would prefer constants.

Update brian asked how hard it is to extend to process other types too, in particular, fixType (enumeration). That turned out to be an addition of a few extra lines. I've also done a few extra modifications so it puts a package declaration at the top, a "1;" at the bottom, and suppression of the junk. The result is here:

XML file (source file):

<?xml version="1.0" encoding="utf-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.topografix.com/GPX/1/1" targetNamespace="http://www.topografix.com/GPX/1/1" elementFormDefault="qualified"> <xsd:simpleType name="longitudeType"> <xsd:annotation> <xsd:documentation> The longitude of the point. Decimal degrees, WGS84 datum. </xsd:documentation> </xsd:annotation> <xsd:restriction base="xsd:decimal"> <xsd:minInclusive value="-180.0"/> <xsd:maxExclusive value="180.0"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="fixType"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="none"/> <xsd:enumeration value="2d"/> <xsd:enumeration value="3d"/> <xsd:enumeration value="dgps"/> <xsd:enumeration value="pps"/> </xsd:restriction> </xsd:simpleType> </xsd:schema>

XSL file:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <xsl:param name="package" select="'Foo'" /> <xsl:output method="text"/> <xsl:template match="/"> package <xsl:value-of select="$package" />; <xsl:apply-templates /> 1; </xsl:template> <xsl:template match="text()" /> <xsl:template match="xsd:simpleType"> sub <xsl:value-of select="@name" /> { <xsl:for-each select="xsd:annotation/xsd:documentation"># <xsl:val +ue-of select="normalize-space(.)" /></xsl:for-each> my($class, $value) = @_; return FALSE if _is_null($value); <xsl:for-each select="xsd:restriction" > return <xsl:value-of select="replace(@base,':', '_')" />($value) +and <xsl:for-each select="xsd:enumeration" ><xsl:if test="position() &gt; 1">|| </xsl:if >$value eq '<xsl:value-of select="replace(replace(@value,'\\','\\\\'), + '''', '\\''')" />' <xsl:if test="position() = last()">and </xsl:if></xsl:for-each ><xsl:apply-templates mode="restriction" select="*" />TRUE; </xsl:for-each> <xsl:if test="count(xsd:restriction) = 0" > return TRUE; </xsl:if>} </xsl:template> <xsl:template mode="restriction" match="xsd:minInclusive">$value &gt;= + <xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:minExclusive">$value &gt; +<xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:maxInclusive">$value &lt;= + <xsl:value-of select="@value" /> and </xsl:template> <xsl:template mode="restriction" match="xsd:maxExclusive">$value &lt; +<xsl:value-of select="@value" /> and </xsl:template> </xsl:stylesheet>

Generated output:

package Foo; sub longitudeType { # The longitude of the point. Decimal degrees, WGS84 datum. my($class, $value) = @_; return FALSE if _is_null($value); return xsd_decimal($value) and $value >= -180.0 and $value < 180.0 + and TRUE; } sub fixType { my($class, $value) = @_; return FALSE if _is_null($value); return xsd_string($value) and $value eq 'none' || $value eq '2d' | +| $value eq '3d' || $value eq 'dgps' || $value eq 'pps' and TRUE; } 1;

p.s. I wrapped the XSL inside the tags in order to avoid generation of extra whitespace, which may make the source look a little strange.


In reply to Re^2: Automatically creating data validation module from XSD by bart
in thread Automatically creating data validation module from XSD by brian_d_foy

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.