Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a schema from an example XML document in Perl?

Tags:

xml

perl

xsd

I need to create a XSD schema based on a XML file. Are there any Perl modules which can do this?

like image 300
Eugene Yarmash Avatar asked Apr 19 '11 12:04

Eugene Yarmash


1 Answers

You can create the XSD by a XSL transformation using any XSLT processor. See XML::XSLT

An XSD file contains two element types: simple and complex. All leaf nodes have to be translated into simple type elements and the others have to be translated into complex types. Leaf nodes are nodes without any descendants. The corresponding XPath is //*[not(descendant::element())]. The following XSLT implements this approch:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
               elementFormDefault="qualified" 
               attributeFormDefault="unqualified">
      <xsl:for-each select="//*[not(descendant::element())]">
        <xsl:element name="xs:element">
          <xsl:attribute name="name">
            <xsl:value-of select="name()"/>
          </xsl:attribute>
          <xs:simpleType>
            <xs:restriction base="xs:string"/>
          </xs:simpleType>
        </xsl:element>
      </xsl:for-each>
      <xsl:for-each select="//*[descendant::element()]">
        <xsl:element name="xs:element">
          <xsl:attribute name="name">
            <xsl:value-of select="name()"/>
          </xsl:attribute>
          <xs:complexType>
            <xs:sequence>
              <xsl:for-each select="child::*">
                <xsl:element name="xs:element">
                  <xsl:attribute name="ref">
                    <xsl:value-of select="name()"/>
                  </xsl:attribute>
                </xsl:element>
              </xsl:for-each>
            </xs:sequence>
          </xs:complexType>
        </xsl:element>
      </xsl:for-each>
    </xs:schema>
  </xsl:template>
</xsl:stylesheet>

The following example:

<?xml version="1.0" encoding="UTF-8"?>
<person>
  <firstname>Peter</firstname>
  <lastname>Pan</lastname>
  <born>
    <year>1904</year>
    <month>12</month>
    <day>27</day>
  </born>
</person>

Will produce the following schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
  <xs:element name="firstname">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>
  <xs:element name="lastname">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>
  <xs:element name="year">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>
  <xs:element name="month">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>
  <xs:element name="day">
    <xs:simpleType>
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
  </xs:element>
  <xs:element name="person">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="firstname"/>
        <xs:element ref="lastname"/>
        <xs:element ref="born"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="born">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="year"/>
        <xs:element ref="month"/>
        <xs:element ref="day"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
like image 164
ceving Avatar answered Oct 24 '22 01:10

ceving