Detect XSD Code Generation Issues
The XSD.EXE command-line tool will generate .NET types from a set of XML Schema files.
However, certain constructs in the XSD will result in faulty .NET code. In particular, <xsd:choice> elements with children that are not exclusively <xsd:element>s are quite likely to have issues in the generated class.
I found that the following XSLT stylesheet proves useful in flagging up potentially-troublesome Schema fragments.
It's not perfect but it's better than scanning schema by eye.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsd="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xsd">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Xml Schema Code Generation Issue Report</title>
<style>
BODY { margin-left: 10px;
margin-right:10px;
font-family:"Verdana", sans-serif;
font-size:x-small;
}
#content { font-size:x-small;
padding-bottom: 2em;
}
.main { position:absolute;
top:80px;
left:80px;
}
#links { position:absolute;
top:158px;
left:45px;
}
dt { font-weight:bold;}
.footer { position:absolute;
top:468px;
left:18px;
width:130px;
color:black;
font-weight:bold;
}
.ie4footer { position:absolute;
top:400px;
left:-160px;
width:130px;
color:black;
font-weight:bold;
}
A:link { color:rgb(78,72,135) }
A:visited { color:rgb(128,128,200) }
A:active { color:rgb(241,96,67) }
A:hover { color:rgb(241,96,67) }
#links A:link { color:rgb(78,72,135); text-decoration:none; }
#links A:visited { color:rgb(78,72,135); text-decoration:none; }
#links A:active { color:white }
#links A:hover {color:white}
.footer A:link { color:rgb(255,170,87) }
.footer A:visited { color:rgb(255,170,87) }
.footer A:active { color:white }
.footer A:hover {color:white}
#editor { position:absolute;
top:80px;
left:200px;
}
#editor DIV { font-size:xx-small;
font-style:italic;
}
.new { background-color:rgb(255,170,87);
color:rgb(52,128,184);
font-size:xx-small;
font-weight:bold;
}
.editor-button { width:18%;
padding:2px;
margin:4;
background-color:#9c0001;
border:2px solid black;
text-align:center;
font-weight:bold;
text-decoration:none;
color:white;
}
.editor-button:visited { color:#9c0001; }
.editor-button:active { color:white; }
.editor-button:hover { color:white; }
.link-title { margin-top:.5em; font-weight:bold }
.link-description { margin-left:2em; font-size:xx-small; }
p { margin-top:.5em;
margin-bottom:.5em;
}
pre { font-size:x-small;
background-color:#DFA894;
margin:1em;
}
table { border:none;
font-size:x-small;
}
td, th
{
border-right: medium none;
padding-right: 2px;
border-top: medium none;
padding-left: 2px;
padding-bottom: 2px;
margin: 2px;
border-left: medium none;
padding-top: 2px;
border-bottom: medium none;
background-color: ffffcc;
text-align: left;
}
th
{
background-color: 9EBBD9;
color: white;
}
ul, ol { margin-top:.5em;
}
h1
{
border-top: cccc99 1px solid;
margin-top: 1em;
padding-left: 4px;
font-size: medium;
margin-bottom: 0.5em;
border-left: cccc99 12px solid;
color: 993300;
background-color: ffffcc;
}
h2, h3, h4, h5, h6
{
margin-bottom: 0.5em;
color: 993300;
background-color: ffffcc;
}
h2 { font-size:small;
margin-top:1em;
border-left:8px solid cccc99;
border-top:1px solid cccc99;
padding-left:4px;
}
h3 { font-size:x-small;
margin-top:1em;
border-left:4px solid cccc99;
border-top:1px solid cccc99;
padding-left:4px;
}
h4 { font-size:x-small;
}
h5 { font-size:xx-small;
}
h6 { font-size:xx-small;
font-style:italic;
}
span.label {
font-weight:bold;
}
</style>
</head>
<body>
<h1>Xml Schema Code Generation Issue Report</h1>
<h2>Target Namespace = {<xsl:value-of select="xsd:schema/@targetNamespace"/>}</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="xsd:choice">
<xsl:variable name="ElementCount">
<xsl:call-template name="GetElementCount"/>
</xsl:variable>
<xsl:variable name="NonElementCount">
<xsl:call-template name="GetNonElementCount"/>
</xsl:variable>
<xsl:variable name="SignificantNonElementCount">
<xsl:call-template name="GetSignificantNonElementCount"/>
</xsl:variable>
<xsl:variable name="HasChoiceCodeGenIssueRtf">
<xsl:call-template name="GetHasChoiceCodeGenIssue"/>
</xsl:variable>
<xsl:variable name="HasChoiceCodeGenIssue" select="$HasChoiceCodeGenIssueRtf = 'true'"/>
<xsl:variable name="BgColour">
<xsl:call-template name="GetBackgroundColour"/>
</xsl:variable>
<div style="Background-color:{$BgColour};">
<h2>Choice element with <xsl:if test="not($HasChoiceCodeGenIssue)">no </xsl:if>issue:</h2>
<xsl:call-template name="elementPath"/>
<br/>
Number of xsd:element children = <xsl:value-of select="$ElementCount"/>
<br/>
Number of non-xsd:element children = <xsl:value-of select="$NonElementCount"/>
<br/>
Number of significant non-xsd:element children = <xsl:value-of select="$SignificantNonElementCount"/>
<br/>
HasChoiceCodeGenIssue = <xsl:value-of select="$HasChoiceCodeGenIssue"/>
<br/>
Is HasChoiceCodeGenIssueRtf = 'true'? = <xsl:value-of select="$HasChoiceCodeGenIssueRtf = 'true'"/>
<br/>
Is HasChoiceCodeGenIssue = boolean(true)? = <xsl:value-of select="$HasChoiceCodeGenIssue"/>
<br/>
</div>
<xsl:apply-templates/>
</xsl:template>
<!-- Number of child xsd:element elements -->
<xsl:template name="GetElementCount">
<xsl:value-of select="count([name(.) = 'xsd:element'])"/>
</xsl:template>
<!-- Number of child non-xsd:element elements -->
<xsl:template name="GetNonElementCount">
<xsl:value-of select="count([name(.) != 'xsd:element'])"/>
</xsl:template>
<!-- Number of child significant non-xsd:element elements -->
<xsl:template name="GetSignificantNonElementCount">
<xsl:value-of select="count([name(.) != 'xsd:element' and name(.) != 'xsd:annotation'])"/>
</xsl:template>
<!-- Detects whether this choice may have a code generation issue -->
<xsl:template name="GetHasChoiceCodeGenIssue">
<xsl:variable name="ElementCount">
<xsl:call-template name="GetElementCount"/>
</xsl:variable>
<xsl:variable name="NonElementCount">
<xsl:call-template name="GetNonElementCount"/>
</xsl:variable>
<xsl:variable name="SignificantNonElementCount">
<xsl:call-template name="GetSignificantNonElementCount"/>
</xsl:variable>
<xsl:value-of select="boolean($ElementCount > 0 and $SignificantNonElementCount > 0)"/>
</xsl:template>
<xsl:template name="GetBackgroundColour">
<xsl:variable name="HasChoiceCodeGenIssueRtf">
<xsl:call-template name="GetHasChoiceCodeGenIssue"/>
</xsl:variable>
<xsl:variable name="HasChoiceCodeGenIssue" select="$HasChoiceCodeGenIssueRtf = 'true'"/>
<xsl:choose>
<xsl:when test="$HasChoiceCodeGenIssue">red</xsl:when>
<xsl:otherwise>lightgreen</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()|@|">
<xsl:apply-templates/>
</xsl:template>
<!-- paths from elements -->
<xsl:template name="elementPath">
<xsl:for-each select="(ancestor-or-self::)">/<xsl:value-of select="name()"/>[<xsl:value-of select="1+count(preceding-sibling::)"/>]
<xsl:if test="@name">(name=<xsl:value-of select="@name"/>)</xsl:if>
<br/>
</xsl:for-each>
</xsl:template>
<!-- paths from attributes -->
<xsl:template name="attributePath">
<xsl:for-each select="parent::">
<xsl:call-template name="elementPath"/>
</xsl:for-each>
<xsl:text>/@</xsl:text>
<xsl:value-of select="name(.)"/>
</xsl:template>
</xsl:stylesheet>