Posted to tcl by mjanssen at Fri Oct 30 13:43:39 GMT 2015view pretty

proc define {element sequence {documentation {}}} {
    if {  [llength $sequence] == 1 &&
          [string range $sequence 0 3] eq "xsd:"
    } {
        emitElement $element $sequence $documentation
        return
    }  
    set typename ${element}Type
    emitElement $element $typename 
    emitTypeDef $typename $sequence $documentation
}  

proc extension {element baseType attributes {documentation {}}} {
    emit [subst {<xsd:element name="$element" type="${element}Type"/>
<xsd:complexType name="${element}Type">
    <xsd:annotation>
        <xsd:documentation>$documentation</xsd:documentation>
    </xsd:annotation>
    <xsd:simpleContent>
        <xsd:extension base="$baseType">
    }]  
    foreach attribute $attributes {
        lassign $attribute name doc 
        emit [ subst {    <xsd:attribute name="$name" use="optional">
                <xsd:annotation>
                    <xsd:documentation>$doc</xsd:documentation>
                </xsd:annotation>
            </xsd:attribute>}]
            
    }
    emit {
            </xsd:extension>
    </xsd:simpleContent>
</xsd:complexType>}

}

proc text text {
    emit $text\n
}

proc include {filename} {
    set f [open $filename]
    fconfigure $f -encoding utf-8
    emit \n[read $f]\n
    close $f
}

proc emitElement {element type {documentation {}}} {
    if {$element eq {}} {
        set cardinality {}
        switch -- [string index $type end] {
            + {
                set type [string range $type 0 end-1 ]
                set cardinality {minOccurs="1" maxOccurs="unbounded"}
            }
            ? {
                set type [string range $type 0 end-1 ]
                set cardinality {minOccurs="0" maxOccurs="1"}
            }
            ! {
                set type [string range $type 0 end-1 ]
                set cardinality {minOccurs="1" maxOccurs="1"}
            }
        }
        emit "<xsd:element $cardinality ref=\"$type\">\n"
    } {
        emit "<xsd:element name=\"$element\" type=\"$type\">\n"
    }
    if {$documentation ne {}} {
        emit "<xsd:annotation>\n"
        emit "<xsd:documentation>$documentation</xsd:documentation>\n"
        emit "</xsd:annotation>\n"
    }
    emit "</xsd:element>\n"
}

proc emitSequence {sequence} {
    emit "<xsd:sequence>\n"
    foreach item $sequence {
        emitElement {} $item
    }
    emit "</xsd:sequence>\n"
}

proc emitTypeDef {type sequence documentation} {
    emit "<xsd:complexType name=\"$type\">\n"
    if {$documentation ne {}} {
        emit "<xsd:annotation>\n"
        emit "<xsd:documentation>$documentation</xsd:documentation>\n"
        emit "</xsd:annotation>\n"
    }
    emitSequence $sequence
    emit "</xsd:complexType>\n"
}

proc emit text {
    append ::result $text
}

if {$argc < 1 || $argc > 2} {
    puts stderr "Usage: tsd2xsd tsd-file ?xsd-file?"
    exit
}


set path [pwd]
cd [file dirname [lindex $argv 1]] 

set result ""
lassign $argv tsd xsd
source -encoding utf-8 $tsd
package require tdom
if {$xsd ne {} } {
    set f [open $xsd w]
    fconfigure $f -encoding utf-8
} else {
    set f stdout
}
puts $f {<?xml version="1.0" encoding="UTF-8"?>}
if {[catch {puts $f [[dom parse $result] asXML]} error]} {
    puts stderr $error
    puts $f $result
}
close $f

cd $path