Eugene Yarmash
Eugene Yarmash

Reputation: 149796

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

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

Upvotes: 6

Views: 1059

Answers (1)

ceving
ceving

Reputation: 23824

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>

Upvotes: 4

Related Questions