Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: Automatically creating data validation module from XSD

by bart (Canon)
on Aug 11, 2007 at 22:33 UTC ( [id://631980]=note: print w/replies, xml ) Need Help??


in reply to Re: Automatically creating data validation module from XSD
in thread Automatically creating data validation module from XSD

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.

Replies are listed 'Best First'.
Re^3: Automatically creating data validation module from XSD (translate)
by pKai (Priest) on Aug 16, 2007 at 10:56 UTC
    It doesn't work in XML Notepad, because of the replace

    MS has only poor support for EXSLT which also is the case for its string extensions of XPath 1.0 (replace).

    Standard XPath 1.0 offers translate (somewhat like tr in Perl). For your purpose just do a s/replace/translate/ and even limited renderer like XML Notepad are satisfied. (tested)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://631980]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (6)
As of 2024-04-16 22:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found