/*
* XML Schema Editor
* This code may be freely modified and distributed.
*
* History:
*
* Version 1.0
* First release, Marc Clifton
*/
/*
* Version 1.0
*
* Quirks:
* 1. Clicking on node A while in the middle of editing node B results in the name being changed for node A (mouse down event handler sets the current node!)
* 2. After editing the schema in the text edit box, you MUST compile otherwise changes will be lost!
* 3. If the tree node doesn't match the schema object, there are blank lines in the XSD file which are causing synchronization problems. Select "Schema/Compile" from menu.
*
* Bugs:
* 1. Editing the name of a complex type adds a "name" to the CT, not the parent element
*
* Features:
* dynamically adjusts for global and local types
* dynamically creates complex types from elements
* selecting a tree node highlights the corresponding XML text
* compiler error window
* xml can be edited directly instead of using the tree
* creates and manages global types list as types are added and removed
* keyboard shortcuts:
* F2-edit node label
* Ctrl-A : add to schema at current node
* Ctrl-T : go to top of schema
* Ctrl-P : got to parent of current node
*
* Notes:
*
* Need to do:
*
* Missing features:
* Auto-scroll edit box to show selected node
* Remember selected node when compiling schema
* Implement XmlSchemaElement minOccurs and maxOccurs with GUI to enter values
* Implement XmlSchemaAttribute fixed and use with GUI to enter values
* Implement XmlSchemaGroup
* ...others?
*
*/
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
namespace xmlSchemaEditor
{
public class SchemaEditor : System.Windows.Forms.Form
{
#region data
private System.Windows.Forms.TreeView tvSchema;
private System.Windows.Forms.ContextMenu tvcmSchema;
private System.Windows.Forms.MenuItem mnuAddElement;
private System.ComponentModel.IContainer components;
private System.Windows.Forms.TextBox edSchema;
private System.Windows.Forms.MenuItem mnuAddSimpleType;
private System.Windows.Forms.MenuItem mnuAddComplexType;
private System.Windows.Forms.MainMenu mainMenu;
private System.Windows.Forms.MenuItem mnuFile;
private System.Windows.Forms.MenuItem mnuNew;
private System.Windows.Forms.MenuItem mnuOpen;
private System.Windows.Forms.MenuItem mnuSave;
private System.Windows.Forms.MenuItem mnuSaveAs;
private System.Windows.Forms.MenuItem mnuExit;
private System.Windows.Forms.MenuItem menuItem2;
private System.Windows.Forms.MenuItem menuItem3;
private System.Windows.Forms.MenuItem mnuAbout;
private System.Windows.Forms.OpenFileDialog openSchemaDialog;
private System.Windows.Forms.ImageList tvImageList;
private System.Windows.Forms.MenuItem mnuAddAnnotation;
private System.Windows.Forms.MenuItem mnuAddAttribute;
private System.Windows.Forms.TextBox edSchemaErrors;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem mnuCompile;
private System.Windows.Forms.GroupBox gbSelectType;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.MenuItem menuItem4;
private System.Windows.Forms.MenuItem mnuRemoveNode;
private System.Windows.Forms.MenuItem menuItem6;
private System.Windows.Forms.MenuItem menuItem7;
private System.Windows.Forms.MenuItem menuItem5;
private System.Windows.Forms.MenuItem menuItem9;
private System.Windows.Forms.ComboBox cbGlobalTypes;
private System.Windows.Forms.ComboBox cbSimpleTypes;
private XmlSchema schema;
private System.Windows.Forms.MenuItem mnuFacetEnumeration;
private System.Windows.Forms.MenuItem mnuFacetMaxExclusive;
private System.Windows.Forms.MenuItem mnuFacetMaxInclusive;
private System.Windows.Forms.MenuItem mnuFacetMinExclusive;
private System.Windows.Forms.MenuItem mnuFacetMinInclusive;
private System.Windows.Forms.MenuItem mnuFacetNumeric;
private System.Windows.Forms.MenuItem mnuFacetPattern;
private System.Windows.Forms.MenuItem mnuFacetWhiteSpace;
private System.Windows.Forms.MenuItem mnuFacetFractionDigits;
private System.Windows.Forms.MenuItem mnuFacetLength;
private System.Windows.Forms.MenuItem mnuFacetMaxLength;
private System.Windows.Forms.MenuItem mnuFacetMinLength;
private System.Windows.Forms.MenuItem mnuFacetTotalDigits;
private System.Windows.Forms.MenuItem mnuAddDocumentation;
private System.Windows.Forms.MenuItem mnuAddAppInfo;
private string prevLabel;
private System.Windows.Forms.SaveFileDialog saveAsSchemaDialog;
private string fileName=null;
enum TreeViewImages {Schema, Element, SimpleType, ComplexType, Annotation, Documentation, AppInfo, Attribute, Facet};
#endregion
#region GlobalElementType
public class GlobalElementType
{
public GlobalElementType(string name, XmlSchemaObject type)
{
this.name=name;
this.type=type;
}
public override string ToString()
{
return name;
}
public string Get()
{
return name;
}
public void Set(string name)
{
this.name=name;
}
public string name;
public XmlSchemaObject type;
}
#endregion
#region SchemaEditor Class
public SchemaEditor()
{
InitializeComponent();
CreateRootNode();
tvSchema.LabelEdit=true;
tvSchema.KeyUp+=new KeyEventHandler(EventTreeViewKeyUp);
tvSchema.BeforeLabelEdit+=new NodeLabelEditEventHandler(PreEventLabelChanged);
tvSchema.AfterLabelEdit+=new NodeLabelEditEventHandler(EventLabelChanged);
tvSchema.MouseDown+=new MouseEventHandler(EventMouseDown);
edSchema.LostFocus+=new EventHandler(EventSchemaTextBoxLostFocus);
schema=new XmlSchema();
CompileSchema();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
static void Main()
{
Application.Run(new SchemaEditor());
}
#endregion
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(SchemaEditor));
this.tvSchema = new System.Windows.Forms.TreeView();
this.tvcmSchema = new System.Windows.Forms.ContextMenu();
this.mnuAddElement = new System.Windows.Forms.MenuItem();
this.mnuAddSimpleType = new System.Windows.Forms.MenuItem();
this.mnuAddComplexType = new System.Windows.Forms.MenuItem();
this.mnuAddAttribute = new System.Windows.Forms.MenuItem();
this.menuItem9 = new System.Windows.Forms.MenuItem();
this.menuItem5 = new System.Windows.Forms.MenuItem();
this.mnuAddAnnotation = new System.Windows.Forms.MenuItem();
this.mnuAddDocumentation = new System.Windows.Forms.MenuItem();
this.mnuAddAppInfo = new System.Windows.Forms.MenuItem();
this.menuItem4 = new System.Windows.Forms.MenuItem();
this.menuItem7 = new System.Windows.Forms.MenuItem();
this.mnuFacetEnumeration = new System.Windows.Forms.MenuItem();
this.mnuFacetMaxExclusive = new System.Windows.Forms.MenuItem();
this.mnuFacetMaxInclusive = new System.Windows.Forms.MenuItem();
this.mnuFacetMinExclusive = new System.Windows.Forms.MenuItem();
this.mnuFacetMinInclusive = new System.Windows.Forms.MenuItem();
this.mnuFacetNumeric = new System.Windows.Forms.MenuItem();
this.mnuFacetFractionDigits = new System.Windows.Forms.MenuItem();
this.mnuFacetLength = new System.Windows.Forms.MenuItem();
this.mnuFacetMaxLength = new System.Windows.Forms.MenuItem();
this.mnuFacetMinLength = new System.Windows.Forms.MenuItem();
this.mnuFacetTotalDigits = new System.Windows.Forms.MenuItem();
this.mnuFacetPattern = new System.Windows.Forms.MenuItem();
this.mnuFacetWhiteSpace = new System.Windows.Forms.MenuItem();
this.menuItem6 = new System.Windows.Forms.MenuItem();
this.mnuRemoveNode = new System.Windows.Forms.MenuItem();
this.tvImageList = new System.Windows.Forms.ImageList(this.components);
this.edSchema = new System.Windows.Forms.TextBox();
this.mainMenu = new System.Windows.Forms.MainMenu();
this.mnuFile = new System.Windows.Forms.MenuItem();
this.mnuNew = new System.Windows.Forms.MenuItem();
this.mnuOpen = new System.Windows.Forms.MenuItem();
this.menuItem3 = new System.Windows.Forms.MenuItem();
this.mnuSave = new System.Windows.Forms.MenuItem();
this.mnuSaveAs = new System.Windows.Forms.MenuItem();
this.menuItem2 = new System.Windows.Forms.MenuItem();
this.mnuExit = new System.Windows.Forms.MenuItem();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.mnuCompile = new System.Windows.Forms.MenuItem();
this.mnuAbout = new System.Windows.Forms.MenuItem();
this.openSchemaDialog = new System.Windows.Forms.OpenFileDialog();
this.edSchemaErrors = new System.Windows.Forms.TextBox();
this.gbSelectType = new System.Windows.Forms.GroupBox();
this.cbGlobalTypes = new System.Windows.Forms.ComboBox();
this.cbSimpleTypes = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.saveAsSchemaDialog = new System.Windows.Forms.SaveFileDialog();
this.gbSelectType.SuspendLayout();
this.SuspendLayout();
//
// tvSchema
//
this.tvSchema.Anchor = ((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left);
this.tvSchema.ContextMenu = this.tvcmSchema;
this.tvSchema.FullRowSelect = true;
this.tvSchema.HideSelection = false;
this.tvSchema.ImageList = this.tvImageList;
this.tvSchema.Location = new System.Drawing.Point(8, 8);
this.tvSchema.Name = "tvSchema";
this.tvSchema.Size = new System.Drawing.Size(280, 432);
this.tvSchema.TabIndex = 0;
this.tvSchema.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.tvSchema_AfterSelect);
//
// tvcmSchema
//
this.tvcmSchema.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuAddElement,
this.mnuAddSimpleType,
this.mnuAddComplexType,
this.mnuAddAttribute,
this.menuItem9,
this.menuItem5,
this.menuItem4,
this.menuItem7,
this.menuItem6,
this.mnuRemoveNode});
//
// mnuAddElement
//
this.mnuAddElement.Index = 0;
this.mnuAddElement.Text = "Element";
this.mnuAddElement.Click += new System.EventHandler(this.mnuAddElement_Click);
//
// mnuAddSimpleType
//
this.mnuAddSimpleType.Index = 1;
this.mnuAddSimpleType.Text = "Simple Type";
this.mnuAddSimpleType.Click += new System.EventHandler(this.mnuAddSimpleType_Click);
//
// mnuAddComplexType
//
this.mnuAddComplexType.Index = 2;
this.mnuAddComplexType.Text = "Complex Type";
this.mnuAddComplexType.Click += new System.EventHandler(this.mnuAddComplexType_Click);
//
// mnuAddAttribute
//
this.mnuAddAttribute.Index = 3;
this.mnuAddAttribute.Text = "Attribute";
this.mnuAddAttribute.Click += new System.EventHandler(this.mnuAddAttribute_Click);
//
// menuItem9
//
this.menuItem9.Index = 4;
this.menuItem9.Text = "-";
//
// menuItem5
//
this.menuItem5.Index = 5;
this.menuItem5.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuAddAnnotation,
this.mnuAddDocumentation,
this.mnuAddAppInfo});
this.menuItem5.Text = "Annotation";
//
// mnuAddAnnotation
//
this.mnuAddAnnotation.Index = 0;
this.mnuAddAnnotation.Text = "Annotation";
this.mnuAddAnnotation.Click += new System.EventHandler(this.mnuAddAnnotation_Click);
//
// mnuAddDocumentation
//
this.mnuAddDocumentation.Index = 1;
this.mnuAddDocumentation.Text = "Documentation";
this.mnuAddDocumentation.Click += new System.EventHandler(this.mnuAddDocumentation_Click);
//
// mnuAddAppInfo
//
this.mnuAddAppInfo.Index = 2;
this.mnuAddAppInfo.Text = "App Info";
this.mnuAddAppInfo.Click += new System.EventHandler(this.mnuAddAppInfo_Click);
//
// menuItem4
//
this.menuItem4.Index = 6;
this.menuItem4.Text = "-";
//
// menuItem7
//
this.menuItem7.Index = 7;
this.menuItem7.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuFacetEnumeration,
this.mnuFacetMaxExclusive,
this.mnuFacetMaxInclusive,
this.mnuFacetMinExclusive,
this.mnuFacetMinInclusive,
this.mnuFacetNumeric,
this.mnuFacetPattern,
this.mnuFacetWhiteSpace});
this.menuItem7.Text = "Facet";
//
// mnuFacetEnumeration
//
this.mnuFacetEnumeration.Index = 0;
this.mnuFacetEnumeration.Text = "Enumeration";
this.mnuFacetEnumeration.Click += new System.EventHandler(this.mnuFacetEnumeration_Click);
//
// mnuFacetMaxExclusive
//
this.mnuFacetMaxExclusive.Index = 1;
this.mnuFacetMaxExclusive.Text = "Max Exclusive";
this.mnuFacetMaxExclusive.Click += new System.EventHandler(this.mnuFacetMaxExclusive_Click);
//
// mnuFacetMaxInclusive
//
this.mnuFacetMaxInclusive.Index = 2;
this.mnuFacetMaxInclusive.Text = "Max Inclusive";
this.mnuFacetMaxInclusive.Click += new System.EventHandler(this.mnuFacetMaxInclusive_Click);
//
// mnuFacetMinExclusive
//
this.mnuFacetMinExclusive.Index = 3;
this.mnuFacetMinExclusive.Text = "Min Exclusive";
this.mnuFacetMinExclusive.Click += new System.EventHandler(this.mnuFacetMinExclusive_Click);
//
// mnuFacetMinInclusive
//
this.mnuFacetMinInclusive.Index = 4;
this.mnuFacetMinInclusive.Text = "Min Inclusive";
this.mnuFacetMinInclusive.Click += new System.EventHandler(this.mnuFacetMinInclusive_Click);
//
// mnuFacetNumeric
//
this.mnuFacetNumeric.Index = 5;
this.mnuFacetNumeric.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuFacetFractionDigits,
this.mnuFacetLength,
this.mnuFacetMaxLength,
this.mnuFacetMinLength,
this.mnuFacetTotalDigits});
this.mnuFacetNumeric.Text = "Numeric";
//
// mnuFacetFractionDigits
//
this.mnuFacetFractionDigits.Index = 0;
this.mnuFacetFractionDigits.Text = "Fraction Digits";
this.mnuFacetFractionDigits.Click += new System.EventHandler(this.mnuFacetFractionDigits_Click);
//
// mnuFacetLength
//
this.mnuFacetLength.Index = 1;
this.mnuFacetLength.Text = "Length";
this.mnuFacetLength.Click += new System.EventHandler(this.mnuFacetLength_Click);
//
// mnuFacetMaxLength
//
this.mnuFacetMaxLength.Index = 2;
this.mnuFacetMaxLength.Text = "Max Length";
this.mnuFacetMaxLength.Click += new System.EventHandler(this.mnuFacetMaxLength_Click);
//
// mnuFacetMinLength
//
this.mnuFacetMinLength.Index = 3;
this.mnuFacetMinLength.Text = "Min Length";
this.mnuFacetMinLength.Click += new System.EventHandler(this.mnuFacetMinLength_Click);
//
// mnuFacetTotalDigits
//
this.mnuFacetTotalDigits.Index = 4;
this.mnuFacetTotalDigits.Text = "Total Digits";
this.mnuFacetTotalDigits.Click += new System.EventHandler(this.mnuFacetTotalDigits_Click);
//
// mnuFacetPattern
//
this.mnuFacetPattern.Index = 6;
this.mnuFacetPattern.Text = "Pattern";
this.mnuFacetPattern.Click += new System.EventHandler(this.mnuFacetPattern_Click);
//
// mnuFacetWhiteSpace
//
this.mnuFacetWhiteSpace.Index = 7;
this.mnuFacetWhiteSpace.Text = "White Space";
this.mnuFacetWhiteSpace.Click += new System.EventHandler(this.mnuFacetWhiteSpace_Click);
//
// menuItem6
//
this.menuItem6.Index = 8;
this.menuItem6.Text = "-";
//
// mnuRemoveNode
//
this.mnuRemoveNode.Index = 9;
this.mnuRemoveNode.Text = "Remove";
this.mnuRemoveNode.Click += new System.EventHandler(this.mnuRemoveNode_Click);
//
// tvImageList
//
this.tvImageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
this.tvImageList.ImageSize = new System.Drawing.Size(16, 16);
this.tvImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("tvImageList.ImageStream")));
this.tvImageList.TransparentColor = System.Drawing.Color.Transparent;
//
// edSchema
//
this.edSchema.AcceptsReturn = true;
this.edSchema.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right);
this.edSchema.HideSelection = false;
this.edSchema.Location = new System.Drawing.Point(296, 8);
this.edSchema.Multiline = true;
this.edSchema.Name = "edSchema";
this.edSchema.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.edSchema.Size = new System.Drawing.Size(640, 432);
this.edSchema.TabIndex = 1;
this.edSchema.Text = "";
this.edSchema.WordWrap = false;
//
// mainMenu
//
this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuFile,
this.menuItem1,
this.mnuAbout});
//
// mnuFile
//
this.mnuFile.Index = 0;
this.mnuFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuNew,
this.mnuOpen,
this.menuItem3,
this.mnuSave,
this.mnuSaveAs,
this.menuItem2,
this.mnuExit});
this.mnuFile.Text = "&File";
//
// mnuNew
//
this.mnuNew.Index = 0;
this.mnuNew.Text = "&New";
this.mnuNew.Click += new System.EventHandler(this.mnuNew_Click);
//
// mnuOpen
//
this.mnuOpen.Index = 1;
this.mnuOpen.Text = "&Open";
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
//
// menuItem3
//
this.menuItem3.Index = 2;
this.menuItem3.Text = "-";
//
// mnuSave
//
this.mnuSave.Index = 3;
this.mnuSave.Text = "&Save";
this.mnuSave.Click += new System.EventHandler(this.mnuSave_Click);
//
// mnuSaveAs
//
this.mnuSaveAs.Index = 4;
this.mnuSaveAs.Text = "Save &As";
this.mnuSaveAs.Click += new System.EventHandler(this.mnuSaveAs_Click);
//
// menuItem2
//
this.menuItem2.Index = 5;
this.menuItem2.Text = "-";
//
// mnuExit
//
this.mnuExit.Index = 6;
this.mnuExit.Text = "E&xit";
this.mnuExit.Click += new System.EventHandler(this.mnuExit_Click);
//
// menuItem1
//
this.menuItem1.Index = 1;
this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.mnuCompile});
this.menuItem1.Text = "&Schema";
//
// mnuCompile
//
this.mnuCompile.Index = 0;
this.mnuCompile.Text = "&Compile";
this.mnuCompile.Click += new System.EventHandler(this.mnuCompile_Click);
//
// mnuAbout
//
this.mnuAbout.Index = 2;
this.mnuAbout.Text = "&About";
this.mnuAbout.Click += new System.EventHandler(this.mnuAbout_Click);
//
// edSchemaErrors
//
this.edSchemaErrors.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right);
this.edSchemaErrors.HideSelection = false;
this.edSchemaErrors.Location = new System.Drawing.Point(296, 448);
this.edSchemaErrors.Multiline = true;
this.edSchemaErrors.Name = "edSchemaErrors";
this.edSchemaErrors.ReadOnly = true;
this.edSchemaErrors.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.edSchemaErrors.Size = new System.Drawing.Size(640, 88);
this.edSchemaErrors.TabIndex = 2;
this.edSchemaErrors.Text = "";
//
// gbSelectType
//
this.gbSelectType.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left);
this.gbSelectType.Controls.AddRange(new System.Windows.Forms.Control[] {
this.cbGlobalTypes,
this.cbSimpleTypes,
this.label2,
this.label1});
this.gbSelectType.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.gbSelectType.Location = new System.Drawing.Point(8, 440);
this.gbSelectType.Name = "gbSelectType";
this.gbSelectType.Size = new System.Drawing.Size(280, 96);
this.gbSelectType.TabIndex = 3;
this.gbSelectType.TabStop = false;
this.gbSelectType.Text = "Select Type";
//
// cbGlobalTypes
//
this.cbGlobalTypes.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.cbGlobalTypes.Location = new System.Drawing.Point(88, 56);
this.cbGlobalTypes.Name = "cbGlobalTypes";
this.cbGlobalTypes.Size = new System.Drawing.Size(168, 21);
this.cbGlobalTypes.Sorted = true;
this.cbGlobalTypes.TabIndex = 3;
this.cbGlobalTypes.SelectedIndexChanged += new System.EventHandler(this.cbGlobalTypes_SelectedIndexChanged);
//
// cbSimpleTypes
//
this.cbSimpleTypes.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.cbSimpleTypes.Items.AddRange(new object[] {
"anyURI",
"base64Binary",
"boolean",
"byte",
"date",
"dateTime",
"decimal",
"double",
"duration",
"ENTITIY",
"float",
"gDay",
"gMonth",
"gMonthDay",
"gYear",
"gYearMonth",
"hexBinary",
"ID",
"IDREF",
"imteger",
"int",
"language",
"long",
"Name",
"NCName",
"negativeInteger",
"NMTOKEN",
"nonNegativeInteger",
"nonPositiveInteger",
"normalizedString",
"NOTATION",
"positiveInteger",
"QName",
"short",
"string",
"time",
"token",
"unsignedByte",
"unsignedInt",
"unsignedLong",
"unsignedShort"});
this.cbSimpleTypes.Location = new System.Drawing.Point(88, 24);
this.cbSimpleTypes.Name = "cbSimpleTypes";
this.cbSimpleTypes.Size = new System.Drawing.Size(168, 21);
this.cbSimpleTypes.Sorted = true;
this.cbSimpleTypes.TabIndex = 2;
this.cbSimpleTypes.SelectedIndexChanged += new System.EventHandler(this.cbSimpleTypes_SelectedIndexChanged);
//
// label2
//
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label2.Location = new System.Drawing.Point(8, 58);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(80, 16);
this.label2.TabIndex = 1;
this.label2.Text = "Global Types:";
//
// label1
//
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label1.Location = new System.Drawing.Point(8, 26);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(80, 16);
this.label1.TabIndex = 0;
this.label1.Text = "Simple Types:";
//
// saveAsSchemaDialog
//
this.saveAsSchemaDialog.DefaultExt = "xsd";
//
// SchemaEditor
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(944, 553);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.gbSelectType,
this.edSchemaErrors,
this.edSchema,
this.tvSchema});
this.Menu = this.mainMenu;
this.Name = "SchemaEditor";
this.Text = "XML Schema Editor";
this.gbSelectType.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
#region Menu Commands
#region Add Facets
// There are several types of facets that can be added to a simple type.
// This code adds a facet and specifies a default value (completely arbitrary)
private void mnuFacetEnumeration_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaEnumerationFacet(), "1", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMaxExclusive_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMaxExclusiveFacet(), "101", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMaxInclusive_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMaxInclusiveFacet(), "100", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMinExclusive_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMinExclusiveFacet(), "0", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMinInclusive_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMinInclusiveFacet(), "1", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetFractionDigits_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaFractionDigitsFacet(), "2", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetLength_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaLengthFacet(), "16", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMaxLength_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMaxLengthFacet(), "16", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetMinLength_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaMinLengthFacet(), "1", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetTotalDigits_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaTotalDigitsFacet(), "8", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetPattern_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaPatternFacet(), "[0-9]", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
private void mnuFacetWhiteSpace_Click(object sender, System.EventArgs e)
{
bool ret=AddFacet(new XmlSchemaWhiteSpaceFacet(), "collapse", TreeViewImages.Facet);
if (!ret)
{
MessageBox.Show("Cannot add an element to this item.");
}
}
#endregion
#region Add Annotation, Documentation, and AppInfo
// create an annotation for the schema or for an annotatable object
private void mnuAddAnnotation_Click(object sender, System.EventArgs e)
{
XmlSchemaAnnotation annot=new XmlSchemaAnnotation();
TreeNode newNode=CreateNode("--annotation--");
// if adding at the schema root level...
if (newNode.Parent==tvSchema.Nodes[0])
{
AddToCollection(schema.Items, annot, newNode, TreeViewImages.Annotation);
}
else
{
// otherwise, get the object as an XmlSchemaAnnotated type
XmlSchemaAnnotated obj=newNode.Parent.Tag as XmlSchemaAnnotated;
if (obj != null)
{
// if it exists, add the annotation
obj.Annotation=annot;
newNode.Tag=annot;
newNode.ImageIndex=(int)TreeViewImages.Annotation;
newNode.SelectedImageIndex=(int)TreeViewImages.Annotation;
CompileSchema();
}
else
{
// otherwise, tell the user annotation cannot be added to this type.
newNode.Parent.Nodes.Remove(newNode);
MessageBox.Show("Cannot create an annotation for this item.");
}
}
}
private void mnuAddDocumentation_Click(object sender, System.EventArgs e)
{
bool success=false;
XmlSchemaAnnotation annot=tvSchema.SelectedNode.Tag as XmlSchemaAnnotation;
// if the parent node is an annotation type...
if (annot != null)
{
// ...then add the documentation type
TreeNode newNode=CreateNode("--documentation--");
XmlSchemaDocumentation doc=new XmlSchemaDocumentation();
doc.Markup=TextToNodeArray("Documentation");
annot.Items.Add(doc);
newNode.Tag=doc;
newNode.ImageIndex=(int)TreeViewImages.Annotation;
newNode.SelectedImageIndex=(int)TreeViewImages.Annotation;
CompileSchema();
success=true;
}
if (!success)
{
// otherwise create the annotation type first
mnuAddAnnotation_Click(sender, e);
annot=tvSchema.SelectedNode.Tag as XmlSchemaAnnotation;
// if successful in adding the annotation type, add the documentation type now
if (annot != null)
{
mnuAddDocumentation_Click(sender, e);
}
}
}
private void mnuAddAppInfo_Click(object sender, System.EventArgs e)
{
bool success=false;
XmlSchemaAnnotation annot=tvSchema.SelectedNode.Tag as XmlSchemaAnnotation;
// if the parent node is an annotation type...
if (annot != null)
{
// ...then add the AppInfo type
TreeNode newNode=CreateNode("--app info--");
XmlSchemaAppInfo doc=new XmlSchemaAppInfo();
doc.Markup=TextToNodeArray("Application Information");
annot.Items.Add(doc);
newNode.Tag=doc;
newNode.ImageIndex=(int)TreeViewImages.Annotation;
newNode.SelectedImageIndex=(int)TreeViewImages.Annotation;
CompileSchema();
success=true;
}
if (!success)
{
// otherwise create the annotation type first
mnuAddAnnotation_Click(sender, e);
annot=tvSchema.SelectedNode.Tag as XmlSchemaAnnotation;
// if successful in creating the annotation type, add the AppInfo type now
if (annot != null)
{
mnuAddAppInfo_Click(sender, e);
}
}
}
#endregion
#region Add Attribute
// Can only be added to schema root as a global or complex type.
// For complex types, the attribute can reference a global type.
// An optional type can be specified referring to a simple type.
// If the type isn't used, the attribute must define a simple type.
private void mnuAddAttribute_Click(object sender, System.EventArgs e)
{
TreeNode newNode=CreateNode("Attribute");
XmlSchemaAttribute attrib=new XmlSchemaAttribute();
attrib.Name="Attribute";
attrib.SchemaTypeName=new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");
// root node?
if (newNode.Parent==tvSchema.Nodes[0])
{
// add to root of schema. An global attribute cannot reference a global type
AddToCollection(schema.Items, attrib, newNode, TreeViewImages.Attribute);
cbGlobalTypes.Items.Add(new GlobalElementType(attrib.Name, attrib));
cbGlobalTypes.Enabled=false;
cbSimpleTypes.SelectedItem=-1;
cbSimpleTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
}
else
{
// an attribute can only be added to a complex type
XmlSchemaComplexType ct=newNode.Parent.Tag as XmlSchemaComplexType;
if (ct != null)
{
// and can reference a global attribute, so enable the global combobox
AddToCollection(ct.Attributes, attrib, newNode, TreeViewImages.Attribute);
cbGlobalTypes.SelectedItem=-1;
cbGlobalTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
cbSimpleTypes.Enabled=true;
}
else
{
newNode.Parent.Nodes.Remove(newNode);
MessageBox.Show("Cannot create an attribute for this item.");
}
}
}
#endregion
#region Add Element
// An element can be added to the schema or to a complex type.
// If adding to an element, convert the element to a complex type.
// An element can be added to a global complex type or to a local complex type.
private void mnuAddElement_Click(object sender, System.EventArgs e)
{
TreeNode newNode=CreateNode("Element");
XmlSchemaElement element=new XmlSchemaElement();
element.Name="Element";
element.SchemaTypeName=new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");
// root node?
if (newNode.Parent==tvSchema.Nodes[0])
{
// add to root of schema. A global element can reference another global type
AddToCollection(schema.Items, element, newNode, TreeViewImages.Element);
cbGlobalTypes.Items.Add(new GlobalElementType(element.Name, element));
cbGlobalTypes.Enabled=true;
cbSimpleTypes.SelectedItem=-1;
cbSimpleTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
}
else
{
// otherwise, an element must be part of a complex type
bool ret=AddToComplexType(newNode.Parent.Tag, element, newNode, TreeViewImages.Element);
if (!ret)
{
// not successful
newNode.Parent.Nodes.Remove(newNode);
MessageBox.Show("Cannot add an element to this item.");
}
else
{
// successful
cbGlobalTypes.SelectedItem=-1;
cbGlobalTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
cbSimpleTypes.Enabled=true;
}
}
}
#endregion
#region Add Simple Type
// A simple type can be added as a global type or as a local member of a complex type.
// A simple type cannot contain elements or attributes.
// Simple types are derived from basic types or other simple types.
// The complex type can either be a global definition or a local complex type.
// When adding to a complex type, the simple type must be wrapped in an element.
private void mnuAddSimpleType_Click(object sender, System.EventArgs e)
{
TreeNode newNode=CreateNode("SimpleType");
XmlSchemaSimpleType simpleType=new XmlSchemaSimpleType();
simpleType.Name="SimpleType";
XmlSchemaSimpleTypeRestriction restriction=new XmlSchemaSimpleTypeRestriction();
restriction.BaseTypeName=new XmlQualifiedName("string", "http://www.w3.org/2001/XMLSchema");
simpleType.Content=restriction;
// root node?
if (newNode.Parent==tvSchema.Nodes[0])
{
// add to root of schema. A global simple type cannot reference another global
AddToCollection(schema.Items, simpleType, newNode, TreeViewImages.SimpleType);
cbGlobalTypes.Items.Add(new GlobalElementType(simpleType.Name, simpleType));
cbGlobalTypes.Enabled=false;
cbSimpleTypes.SelectedItem=-1;
cbSimpleTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
}
else
{
// if not a root node, then it must be created as an element of simple type...
XmlSchemaElement el=new XmlSchemaElement();
el.Name="SimpleType";
el.SchemaType=simpleType;
simpleType.Name=null;
// ...as a subnode to a complex type
bool ret=AddToComplexType(newNode.Parent.Tag, el, newNode, TreeViewImages.SimpleType);
if (!ret)
{
// failure
newNode.Parent.Nodes.Remove(newNode);
MessageBox.Show("Cannot add a simple type to this item.");
}
else
{
// success. Can reference a global simple type
cbGlobalTypes.SelectedItem=-1;
cbGlobalTypes.Enabled=true;
cbSimpleTypes.SelectedItem="string";
cbSimpleTypes.Enabled=true;
}
}
}
#endregion
#region Add Complex Type
// A complex type can be added as a global type to the schema or as a complex element.
// If adding to an element, change the element to a complex type.
// When adding to a complex type, the complex type must be wrapped in an element.
private void mnuAddComplexType_Click(object sender, System.EventArgs e)
{
TreeNode newNode=CreateNode("ComplexType");
XmlSchemaComplexType complexType=new XmlSchemaComplexType();
XmlSchemaSequence sequence=new XmlSchemaSequence();
complexType.Particle=sequence;
complexType.Name="ComplexType";
// root node?
if (newNode.Parent==tvSchema.Nodes[0])
{
// add to root. A complex type has no type reference information.
AddToCollection(schema.Items, complexType, newNode, TreeViewImages.ComplexType);
cbGlobalTypes.Items.Add(new GlobalElementType(complexType.Name, complexType));
cbSimpleTypes.SelectedItem=-1;
cbGlobalTypes.SelectedItem=-1;
cbSimpleTypes.Enabled=false;
cbGlobalTypes.Enabled=false;
}
else
{
// if not at root, create an element of complex type...
XmlSchemaElement el=new XmlSchemaElement();
el.Name="ComplexType";
el.SchemaType=complexType;
complexType.Name=null;
// ...that is added as a subnode to a complex type.
bool ret=AddToComplexType(newNode.Parent.Tag, el, newNode, TreeViewImages.ComplexType);
if (!ret)
{
// failure
newNode.Parent.Nodes.Remove(newNode);
MessageBox.Show("Cannot add a complex type to this item.");
}
else
{
// success. No type is referenced.
cbSimpleTypes.SelectedItem=-1;
cbGlobalTypes.SelectedItem=-1;
cbSimpleTypes.Enabled=false;
cbGlobalTypes.Enabled=false;
}
}
}
#endregion
#region New
private void mnuNew_Click(object sender, System.EventArgs e)
{
CreateRootNode(); // create a new treeview root node
schema=new XmlSchema(); // create a new schema
CompileSchema(); // compile and show it
fileName=null; // no filename
}
#endregion
#region Open
// open an existing XSD file
private void mnuOpen_Click(object sender, System.EventArgs e)
{
openSchemaDialog.DefaultExt="xsd";
openSchemaDialog.CheckFileExists=true;
openSchemaDialog.Filter="XSD Files (*.xsd)|*.xsd|All Files (*.*)|*.*";
DialogResult res=openSchemaDialog.ShowDialog();
if (res==DialogResult.OK)
{
try
{
StreamReader tr=new StreamReader(openSchemaDialog.FileName);
schema=XmlSchema.Read(tr, new ValidationEventHandler(SchemaValidationHandler));
tr.Close();
CompileSchema();
CreateRootNode();
DecodeSchema(schema, tvSchema.Nodes[0]);
tvSchema.ExpandAll();
fileName=openSchemaDialog.FileName;
}
catch(Exception err)
{
edSchemaErrors.Text=err.ToString();
}
}
}
#endregion
#region Save, Save As, Exit, About
// save the current XSD
private void mnuSave_Click(object sender, System.EventArgs e)
{
if (fileName==null)
{
mnuSaveAs_Click(sender, e);
}
else
{
CompileSchema();
StreamWriter sw=new StreamWriter(fileName, false, System.Text.Encoding.UTF8);
sw.Write(edSchema.Text);
sw.Flush();
sw.Close();
}
}
// save the current XSD as...
private void mnuSaveAs_Click(object sender, System.EventArgs e)
{
DialogResult res=saveAsSchemaDialog.ShowDialog();
if (res==DialogResult.OK)
{
fileName=saveAsSchemaDialog.FileName;
CompileSchema();
StreamWriter sw=new StreamWriter(fileName, false, System.Text.Encoding.UTF8);
sw.Write(edSchema.Text);
sw.Flush();
sw.Close();
}
}
private void mnuExit_Click(object sender, System.EventArgs e)
{
Close(); // signal form to close
}
// info
private void mnuAbout_Click(object sender, System.EventArgs e)
{
MessageBox.Show("XML Schema Editor\r\n\r\nversion 1.0\r\n\r\n(c)2003 Marc Clifton\r\n\r\nThis program may be freely distributed.");
}
#endregion
#region Compile
private void mnuCompile_Click(object sender, System.EventArgs e)
{
// 1. read the XSD from the edit box into a schema
// 2. compile it
// 3. create a new tree view
// 4. decode the schema into the tree view
// 5. show the tree
try
{
StringReader sr=new StringReader(edSchema.Text);
schema=XmlSchema.Read(sr, new ValidationEventHandler(SchemaValidationHandler));
CompileSchema();
CreateRootNode();
DecodeSchema(schema, tvSchema.Nodes[0]);
tvSchema.ExpandAll();
}
catch(Exception err)
{
edSchemaErrors.Text=err.ToString();
}
}
#endregion
#region Remove Node
// The parent type determines from what list the selected item must be removed.
// Use the image index in the tree view to figure out the parent type.
private void mnuRemoveNode_Click(object sender, System.EventArgs e)
{
TreeNode tnParent=tvSchema.SelectedNode.Parent;
XmlSchemaObject obj=tvSchema.SelectedNode.Tag as XmlSchemaObject;
bool success=false;
// if the node to remove has a parent and is of an XmlSchemaObject type...
if ( (tnParent != null) && (obj != null) )
{
// look at the tree node image index to figure out what the parent is!
switch ((TreeViewImages)tnParent.ImageIndex)
{
// if the parent is the schema root:
case TreeViewImages.Schema:
{
// remove the object from the schema and from the global list
schema.Items.Remove(obj);
int idx=cbGlobalTypes.FindStringExact(tvSchema.SelectedNode.Text);
if (idx != -1)
{
cbGlobalTypes.Items.RemoveAt(idx);
}
success=true;
break;
}
// if the parent is an annotation type
case TreeViewImages.Annotation:
{
XmlSchemaAnnotation annot=tnParent.Tag as XmlSchemaAnnotation;
if (annot != null)
{
annot.Items.Remove(obj);
success=true;
}
break;
}
// if the parent is a simple type
case TreeViewImages.SimpleType:
{
// a simple type can have an annotation or a facet type as children
XmlSchemaSimpleType st=tnParent.Tag as XmlSchemaSimpleType;
if (obj is XmlSchemaAnnotation)
{
// remove from annotation list if it's an annotation type
st.Annotation.Items.Remove(obj);
success=true;
}
else if (obj is XmlSchemaFacet)
{
XmlSchemaSimpleTypeRestriction rest=st.Content as XmlSchemaSimpleTypeRestriction;
if (rest != null)
{
// remove from facet list if it's a facet type
rest.Facets.Remove(obj);
success=true;
}
}
break;
}
// if the parent is a complex type...
case TreeViewImages.ComplexType:
{
XmlSchemaComplexType ct=tnParent.Tag as XmlSchemaComplexType;
if (ct != null)
{
// then we are removing an attribute
if (obj is XmlSchemaAttribute)
{
ct.Attributes.Remove(obj);
success=true;
}
// or an annotation
else if (obj is XmlSchemaAnnotation)
{
ct.Annotation.Items.Remove(obj);
success=true;
}
// or an element type
else
{
XmlSchemaSequence seq=ct.Particle as XmlSchemaSequence;
if (seq != null)
{
seq.Items.Remove(obj);
success=true;
}
}
}
break;
}
}
}
// if successful, remove the node from the tree view
if (success)
{
tnParent.Nodes.Remove(tvSchema.SelectedNode);
CompileSchema();
}
else
{
MessageBox.Show("Unable to remove this node");
}
}
#endregion
#endregion
#region Schema Validation Handler
// report any errors to the schema error edit box
private void SchemaValidationHandler(object sender, ValidationEventArgs args)
{
Console.WriteLine(args.Message);
edSchemaErrors.Text+=args.Message+"\r\n";
}
#endregion
#region Events
#region TreeView PreEventLabelChanged and EventLabelChanged
// exclude certain tree nodes from being editable
private void PreEventLabelChanged(object sender, NodeLabelEditEventArgs e)
{
prevLabel=tvSchema.SelectedNode.Text;
if ( (e.Node.Tag is XmlSchemaFacet) ||
(e.Node.Tag is XmlSchemaAnnotation) ||
(e.Node.Tag is XmlSchemaDocumentation) ||
(e.Node.Tag is XmlSchemaAppInfo) )
{
e.Node.EndEdit(false);
}
}
private void EventLabelChanged(object sender, NodeLabelEditEventArgs e)
{
// if a node is selected...
if (e.Node != null)
{
// and a label has been changed... (e.Label==null if ESC key pressed)
if (e.Label != null)
{
// then change the name of the type in the schema
UpdateTypeAndName(null, e.Label, null);
// if this is a root node...
if (e.Node.Parent == tvSchema.Nodes[0])
{
// ...then also change the name in the global list
// (this is not case sensitive!)
int idx=cbGlobalTypes.FindStringExact(prevLabel);
if (idx != -1)
{
cbGlobalTypes.Items[idx]=new GlobalElementType(e.Label, ((GlobalElementType)cbGlobalTypes.Items[idx]).type);
}
}
}
}
}
#endregion
#region EventTreeViewKeyPress
// shortcuts:
// F2 - edit tree node label
// Ctrl+A - bring up popup menu to Add a subnode
// Ctrl+T - go to Top of tree
// Ctrl+P - go to Parent of currently selected node
private void EventTreeViewKeyUp(object sender, KeyEventArgs e)
{
e.Handled=false;
// F2
if (e.KeyCode==Keys.F2)
{
if (tvSchema.SelectedNode != tvSchema.Nodes[0])
{
tvSchema.SelectedNode.BeginEdit();
e.Handled=true;
}
}
// Ctrl+A
else if ( (e.KeyCode==Keys.A) && (e.Modifiers==Keys.Control) )
{
e.Handled=true;
tvcmSchema.Show(this, tvSchema.Location+new Size(50, 50));
}
// Ctrl+T
else if ( (e.KeyCode==Keys.T) && (e.Modifiers==Keys.Control) )
{
e.Handled=true;
tvSchema.SelectedNode=tvSchema.Nodes[0];
}
// Ctrl+P
else if ( (e.KeyCode==Keys.P) && (e.Modifiers==Keys.Control) )
{
e.Handled=true;
TreeNode node=tvSchema.SelectedNode.Parent;
if (node != null)
{
tvSchema.SelectedNode=node;
}
}
}
#endregion
#region Schema Text Box Lost Focus
private void EventSchemaTextBoxLostFocus(object sender, EventArgs e)
{
mnuCompile_Click(sender, e);
}
#endregion
#region TreeView MouseDown
// On a mouse down, we want to select the node on which the mouse clicked.
// This way we know what node the user right-clicked on when adding sub-nodes
private void EventMouseDown(object sender, MouseEventArgs e)
{
TreeNode tn=tvSchema.GetNodeAt(e.X, e.Y);
if (tn != null)
{
tvSchema.SelectedNode=tn;
}
}
#endregion
#region TreeView AfterSelect
// After selecting a node, we want to:
// 1. highlight the line in the schema that corresponds to the tree node
// 2. update the simple and global type combo boxes to show what the type is for the selected node.
private void tvSchema_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
XmlSchemaObject obj=e.Node.Tag as XmlSchemaObject;
// if this is a schema object...
if (obj != null)
{
// find the corresponding line in the XSD source and highlight it
if ( (obj.LineNumber != 0) && (obj.LineNumber < edSchema.Lines.Length) )
{
int length=0;
for (int i=0; i<obj.LineNumber-1; i++)
{
// get the length of the line including CRLF
length+=edSchema.Lines[i].Length+2;
}
// highlight the line
edSchema.Select(length, edSchema.Lines[obj.LineNumber-1].Length);
}
// Update simple and global type combo boxes.
// Get the name of the element type so that we can find it in the simple or global type list
XmlQualifiedName name=null; // assume failure
if (obj is XmlSchemaAttribute)
{
// this is easy.
name=((XmlSchemaAttribute)obj).SchemaTypeName;
}
else if (obj is XmlSchemaSimpleType)
{
// if it's a simple type, get the restriction type, if it exists
XmlSchemaSimpleTypeRestriction restriction=((XmlSchemaSimpleType)obj).Content as XmlSchemaSimpleTypeRestriction;
if (restriction != null)
{
name=restriction.BaseTypeName;
}
}
else if (obj is XmlSchemaElement)
{
// if it's an element, determine if it's a simple type subnode of a complex type...
// and then get the restriction type, if it exists
XmlSchemaElement el=obj as XmlSchemaElement;
if (el.SchemaType is XmlSchemaSimpleType)
{
XmlSchemaSimpleType st=el.SchemaType as XmlSchemaSimpleType;
XmlSchemaSimpleTypeRestriction rest=st.Content as XmlSchemaSimpleTypeRestriction;
if (rest != null)
{
name=rest.BaseTypeName;
}
}
else
{
// otherwise get the element name
name=el.SchemaTypeName;
// if the name is null, then there must be a reference instead
if (name.Name=="")
{
name=el.RefName;
}
}
}
// select the name from either the simple type list or the global element type list
if (name != null)
{
// see if the name exists in the simple type list
int idx=cbSimpleTypes.FindStringExact(name.Name);
cbSimpleTypes.SelectedIndex=idx;
cbSimpleTypes.Enabled=true;
// see if the name exists in the complex type list
idx=cbGlobalTypes.FindStringExact(name.Name);
cbGlobalTypes.SelectedIndex=idx;
cbGlobalTypes.Enabled=true;
}
else
{
// if there is no name, then disable the comboboxes
cbSimpleTypes.SelectedIndex=-1;
cbGlobalTypes.SelectedIndex=-1;
cbSimpleTypes.Enabled=false;
cbGlobalTypes.Enabled=false;
}
}
else
{
// if this isn't a schema object, then disable the comboboxes
cbSimpleTypes.SelectedIndex=-1;
cbGlobalTypes.SelectedIndex=-1;
cbSimpleTypes.Enabled=false;
cbGlobalTypes.Enabled=false;
}
}
#endregion
#region cbSimpleTypes Index Changed
// the user has selected a simple type. Select it and clear the global type combo box.
private void cbSimpleTypes_SelectedIndexChanged(object sender, System.EventArgs e)
{
if (cbSimpleTypes.SelectedIndex != -1)
{
UpdateTypeAndName(cbSimpleTypes.SelectedItem.ToString(), null, "http://www.w3.org/2001/XMLSchema");
cbGlobalTypes.SelectedIndex=-1;
}
}
#endregion
#region cbGlobalTypes Index Changed
// the user has selected a global type. Select it and clear the simple type combo box.
private void cbGlobalTypes_SelectedIndexChanged(object sender, System.EventArgs e)
{
if (cbGlobalTypes.SelectedIndex != -1)
{
UpdateTypeAndName(cbGlobalTypes.SelectedItem.ToString(), null, null);
cbSimpleTypes.SelectedIndex=-1;
}
}
#endregion
#endregion
#region Misc. Helpers
#region CreateRootNode
// This helper function destroys the existing tree and creates a new tree.
// It also clears the global type list, since there are no global types defined
// with a blank tree.
private void CreateRootNode()
{
tvSchema.Nodes.Clear();
TreeNode rootNode=new TreeNode("Schema:");
tvSchema.Nodes.Add(rootNode);
rootNode.ImageIndex=(int)TreeViewImages.Schema;
rootNode.SelectedImageIndex=(int)TreeViewImages.Schema;
cbGlobalTypes.Items.Clear();
}
#endregion
#region CompileSchema
// Compile the schema as it exists in the XmlSchema structure, displaying any
// errors in the schema error edit box and displaying the schema itself in
// the schema edit box.
private void CompileSchema()
{
edSchemaErrors.Text="";
schema.Compile(new ValidationEventHandler(SchemaValidationHandler));
StringWriter sw=new StringWriter();
schema.Write(sw);
edSchema.Text=sw.ToString();
}
#endregion
#region CreateNode
// This helper function creates a subnode off of the selected node and requests
// that the node label be immediately editable.
private TreeNode CreateNode(string name)
{
TreeNode tn=tvSchema.SelectedNode;
TreeNode newNode=new TreeNode(name);
tn.Nodes.Add(newNode);
tn.Expand();
tvSchema.SelectedNode=newNode;
newNode.BeginEdit();
return newNode;
}
#endregion
#region AddToCollection
// Add a schema type to the specified schema object collection.
// The tree node references the schema type being added.
// The image indices are set.
// The schema is recompiled, which shows any errors and updates the schema display.
void AddToCollection(XmlSchemaObjectCollection coll, XmlSchemaObject obj, TreeNode node, TreeViewImages imgIdx)
{
coll.Add(obj);
node.Tag=obj;
node.ImageIndex=(int)imgIdx;
node.SelectedImageIndex=(int)imgIdx;
CompileSchema();
}
#endregion
#region ChangeElementToComplexType
// When adding a subnode to an element or a simple type, the node must be changed to a complex type.
private XmlSchemaComplexType ChangeElementToComplexType(XmlSchemaElement el, TreeNode tn)
{
// if the element is currently a reference, we need to remove the reference
// and set the name to something, which in this case is the old ref name.
if (el.RefName != null)
{
el.Name=el.RefName.Name;
el.RefName=null;
}
// creat the complex type.
XmlSchemaComplexType ct=new XmlSchemaComplexType();
el.SchemaType=ct;
// a complex type cannot have a type name
el.SchemaTypeName=null;
// create the sequence
XmlSchemaSequence sequence=new XmlSchemaSequence();
ct.Particle=sequence;
// update the image indices
tn.ImageIndex=(int)TreeViewImages.ComplexType;
tn.SelectedImageIndex=(int)TreeViewImages.ComplexType;
return ct;
}
#endregion
#region AddToComplexType
// add a type to a complex type
private bool AddToComplexType(object obj, XmlSchemaObject item, TreeNode newNode, TreeViewImages imgIdx)
{
bool success=true;
XmlSchemaElement el=obj as XmlSchemaElement;
XmlSchemaComplexType complexType=obj as XmlSchemaComplexType;
// is it an element...
if (el != null)
{
// of complex type (so we know it's a local complex type, not a global one!)
XmlSchemaComplexType ct=el.SchemaType as XmlSchemaComplexType;
if (ct != null)
{
// does it have a sequence?
XmlSchemaSequence seq=ct.Particle as XmlSchemaSequence;
if (seq != null)
{
// yes--add it to the sequence collection
AddToCollection(seq.Items, item, newNode, imgIdx);
}
else
{
// no--we can't add it.
MessageBox.Show("Complex type is missing sequence!");
success=false;
}
}
else
{
// change the basic element to a complex type by adding a sequence and then
// add the sub-element
ct=ChangeElementToComplexType(el, newNode.Parent);
AddToCollection(((XmlSchemaSequence)ct.Particle).Items, item, newNode, imgIdx);
}
}
// or is it a global complex type...
else if (complexType != null)
{
XmlSchemaSequence seq=complexType.Particle as XmlSchemaSequence;
// which should have a sequence!
if (seq != null)
{
// yes--add it to the collection
AddToCollection(seq.Items, item, newNode, imgIdx);
}
else
{
// no--we can't add it.
MessageBox.Show("Complex type is missing sequence!");
success=false;
}
}
else
{
// failure--current node is not an element and not a complex type
success=false;
}
return success;
}
#endregion
#region UpdateTypeAndName
// This is a dual purpose function that updates either the type or the name.
// It can also update both at once, but isn't used in that way in this program.
// Pass in a null for typeName if only changing the name.
// Pass in a null for name if only changing the typeName.
// Pass in a null for the nameSpace if the typeName is a global type.
private void UpdateTypeAndName(string typeName, string name, string nameSpace)
{
// Is the type referenced by the tree node an XmlSchemaObject?
XmlSchemaObject obj=tvSchema.SelectedNode.Tag as XmlSchemaObject;
if (obj != null)
{
// is it an attribute?
if (obj is XmlSchemaAttribute)
{
XmlSchemaAttribute attrib=obj as XmlSchemaAttribute;
// if we're changing the name:
if (name != null)
{
attrib.Name=name;
CompileSchema();
}
// if we're changing the type:
if (typeName != null)
{
// if the name refers to a global attribute, then use ref instead of type
int idx=cbGlobalTypes.FindStringExact(typeName);
GlobalElementType glet=null;
if (idx != -1)
{
glet=cbGlobalTypes.Items[idx] as GlobalElementType;
}
// if a global exists of this type...
if ( (glet != null) && (glet.type is XmlSchemaAttribute) )
{
// then get rid of the type name and use a ref instead
attrib.SchemaTypeName=null;
attrib.RefName=new XmlQualifiedName(typeName, nameSpace);
// can't have a name
attrib.Name=null;
}
else
{
// otherwise, use a type name and get rid of the ref
attrib.SchemaTypeName=new XmlQualifiedName(typeName, nameSpace);
attrib.RefName=null;
if (attrib.Name==null)
{
// if changing from ref to type, we need some sort of default name
attrib.Name=tvSchema.SelectedNode.Text;
}
}
CompileSchema();
// update the tree node name
tvSchema.SelectedNode.Text=attrib.QualifiedName.Name;
}
}
// is it an element?
else if (obj is XmlSchemaElement)
{
XmlSchemaElement el=obj as XmlSchemaElement;
// if we're changing the name:
if (name != null)
{
el.Name=name;
CompileSchema();
}
// if we're changing the type:
if (typeName != null)
{
if (el.SchemaType is XmlSchemaSimpleType)
{
XmlSchemaSimpleType st=el.SchemaType as XmlSchemaSimpleType;
XmlSchemaSimpleTypeRestriction rest=st.Content as XmlSchemaSimpleTypeRestriction;
if (rest != null)
{
rest.BaseTypeName=new XmlQualifiedName(typeName, nameSpace);
CompileSchema();
}
}
else
{
// if the name refers to a global element, then use ref instead of type
// Same deal as for changing the element type name.
// Since the SchemaTypeName and RefName are not part of any base class shared
// between the SchemaXmlAttribute and SchemaXmlElement, we need separate code.
int idx=cbGlobalTypes.FindStringExact(typeName);
GlobalElementType glet=null;
if (idx != -1)
{
glet=cbGlobalTypes.Items[idx] as GlobalElementType;
}
if ( (glet != null) && (glet.type is XmlSchemaElement) )
{
el.SchemaTypeName=null;
el.RefName=new XmlQualifiedName(typeName, nameSpace);
el.Name=null;
}
else
{
el.SchemaTypeName=new XmlQualifiedName(typeName, nameSpace);
el.RefName=null;
if (el.Name==null)
{
el.Name=tvSchema.SelectedNode.Text;
}
}
CompileSchema();
tvSchema.SelectedNode.Text=el.QualifiedName.Name;
}
}
}
// is it a simple type?
else if (obj is XmlSchemaSimpleType)
{
XmlSchemaSimpleType st=obj as XmlSchemaSimpleType;
// if we're changing the name:
if (name != null)
{
st.Name=name;
CompileSchema();
}
// if we're changing the type name:
if (typeName != null)
{
// this must be done in the Restriction object
XmlSchemaSimpleTypeRestriction restriction=st.Content as XmlSchemaSimpleTypeRestriction;
if (restriction != null)
{
restriction.BaseTypeName=new XmlQualifiedName(typeName, nameSpace);
CompileSchema();
cbGlobalTypes.SelectedIndex=-1;
}
}
}
// is it a complex type?
else if (obj is XmlSchemaComplexType)
{
// if we're changing the name:
if (name != null)
{
((XmlSchemaComplexType)obj).Name=name;
CompileSchema();
}
// there is no such thing as changing the type of a complex type
}
}
}
#endregion
#region Add Facet
// Add a facet to a simple type.
bool AddFacet(XmlSchemaFacet facet, string val, TreeViewImages imgIdx)
{
// get the simple type.
XmlSchemaSimpleType st=tvSchema.SelectedNode.Tag as XmlSchemaSimpleType;
// assume failure
XmlSchemaSimpleTypeRestriction rs=null;
bool success=false;
// if the simple type exists, get the restriction type
if (st != null)
{
rs=st.Content as XmlSchemaSimpleTypeRestriction;
}
// if the restriction type exists...
if (rs != null)
{
// create the node and add it to the facet collection
TreeNode newNode=CreateNode(facet.ToString());
facet.Value=val;
rs.Facets.Add(facet);
CompileSchema();
success=true;
}
return success;
}
#endregion
#region TextToNodeArray
// a helper to create some default documentation text.
public static XmlNode[] TextToNodeArray(string text)
{
XmlDocument doc = new XmlDocument();
return new XmlNode[1] {doc.CreateTextNode(text)};
}
#endregion
#endregion
#region DecodeSchema
// stub that wraps the actual decoding in a try block so we can display errors
private void DecodeSchema(XmlSchema schema, TreeNode node)
{
try
{
DecodeSchema2(schema, node);
}
catch(Exception err)
{
edSchemaErrors.Text=err.ToString();
}
}
// recursive decoder
private TreeNode DecodeSchema2(XmlSchemaObject obj, TreeNode node)
{
TreeNode newNode=node;
// convert the object to all types and then check what type actually exists
XmlSchemaAnnotation annot=obj as XmlSchemaAnnotation;
XmlSchemaAttribute attrib=obj as XmlSchemaAttribute;
XmlSchemaFacet facet=obj as XmlSchemaFacet;
XmlSchemaDocumentation doc=obj as XmlSchemaDocumentation;
XmlSchemaAppInfo appInfo=obj as XmlSchemaAppInfo;
XmlSchemaElement element=obj as XmlSchemaElement;
XmlSchemaSimpleType simpleType=obj as XmlSchemaSimpleType;
XmlSchemaComplexType complexType=obj as XmlSchemaComplexType;
// If the current node is the root node of the tree, then we are
// possibly adding a global attribute, element, simple type, or complex type.
if (node==tvSchema.Nodes[0])
{
if (attrib != null)
{
if (attrib.Name != null)
{
// add to global list
cbGlobalTypes.Items.Add(new GlobalElementType(attrib.Name, attrib));
}
}
else if (element != null)
{
if (element.Name != null)
{
// add to global list
cbGlobalTypes.Items.Add(new GlobalElementType(element.Name, element));
}
}
else if (simpleType != null)
{
if (simpleType.Name != null)
{
// add to global list
cbGlobalTypes.Items.Add(new GlobalElementType(simpleType.Name, simpleType));
}
}
else if (complexType != null)
{
if (complexType.Name != null)
{
// add to global list
cbGlobalTypes.Items.Add(new GlobalElementType(complexType.Name, complexType));
}
}
}
// if annotation, add a tree node and recurse for documentation and app info
if (annot != null)
{
newNode=new TreeNode("--annotation--");
newNode.Tag=annot;
newNode.ImageIndex=4;
newNode.SelectedImageIndex=4;
node.Nodes.Add(newNode);
foreach (XmlSchemaObject schemaObject in annot.Items)
{
DecodeSchema2(schemaObject, newNode);
}
}
else
// if attribute, add a tree node
if (attrib != null)
{
newNode=new TreeNode(attrib.QualifiedName.Name);
newNode.Tag=attrib;
newNode.ImageIndex=7;
newNode.SelectedImageIndex=7;
node.Nodes.Add(newNode);
}
else
// if facet, add a tree node
if (facet != null)
{
newNode=new TreeNode(facet.ToString());
newNode.Tag=facet;
newNode.ImageIndex=8;
newNode.SelectedImageIndex=8;
node.Nodes.Add(newNode);
}
else
// if documentation, add a tree node
if (doc != null)
{
newNode=new TreeNode("--documentation--");
newNode.Tag=doc;
newNode.ImageIndex=5;
newNode.SelectedImageIndex=5;
node.Nodes.Add(newNode);
}
else
// if app info, add a tree node
if (appInfo != null)
{
newNode=new TreeNode("--app info--");
newNode.Tag=annot;
newNode.ImageIndex=6;
newNode.SelectedImageIndex=6;
node.Nodes.Add(newNode);
}
else
// if an element, determine whether the element is a simple type or a complex type
if (element != null)
{
XmlSchemaSimpleType st=element.SchemaType as XmlSchemaSimpleType;
XmlSchemaComplexType ct=element.SchemaType as XmlSchemaComplexType;
if (st != null)
{
// this is a simple type element. Recurse.
TreeNode node2=DecodeSchema2(st, newNode);
node2.Text=element.Name;
}
else if (ct != null)
{
// this is a complex type element. Recurse.
TreeNode node2=DecodeSchema2(ct, newNode);
node2.Text=element.Name;
}
else
{
// This is a plain ol' fashioned element.
newNode=new TreeNode(element.QualifiedName.Name);
newNode.Tag=element;
newNode.ImageIndex=1;
newNode.SelectedImageIndex=1;
node.Nodes.Add(newNode);
}
}
else
// if a simple type, then add a tree node and recurse facets
if (simpleType != null)
{
newNode=new TreeNode(simpleType.QualifiedName.Name);
newNode.Tag=simpleType;
newNode.ImageIndex=2;
newNode.SelectedImageIndex=2;
node.Nodes.Add(newNode);
XmlSchemaSimpleTypeRestriction rest=simpleType.Content as XmlSchemaSimpleTypeRestriction;
if (rest != null)
{
foreach (XmlSchemaFacet schemaObject in rest.Facets)
{
DecodeSchema2(schemaObject, newNode);
}
}
}
else
// if a complex type, add a tree node and recurse its sequence
if (complexType != null)
{
newNode=new TreeNode(complexType.Name);
newNode.Tag=complexType;
newNode.ImageIndex=3;
newNode.SelectedImageIndex=3;
node.Nodes.Add(newNode);
XmlSchemaSequence seq=complexType.Particle as XmlSchemaSequence;
if (seq != null)
{
foreach (XmlSchemaObject schemaObject in seq.Items)
{
DecodeSchema2(schemaObject, newNode);
}
}
}
// now recurse any object collection of the type.
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
if (property.PropertyType.FullName == "System.Xml.Schema.XmlSchemaObjectCollection")
{
XmlSchemaObjectCollection childObjectCollection=(XmlSchemaObjectCollection) property.GetValue(obj, null);
foreach (XmlSchemaObject schemaObject in childObjectCollection)
{
DecodeSchema2(schemaObject, newNode);
}
}
}
return newNode;
}
#endregion
}
}