XML 架构定义(XSD) 编辑器






4.89/5 (81投票s)
2003 年 1 月 21 日
5分钟阅读

420079

11119
一个能够生成常见 XSD 文档的编辑器
目录
引言
本文介绍了一个 XML Schema Definition (XSD) 文档的编辑器,该编辑器使用 C# 和 .NET 的 XmlSchema 类实现。我在网上搜索,只找到了一个这样的编辑器:XML Architect[^]。我发现 VS.NET 中包含的编辑器与数据库模式编辑器过于相似。我个人认为 XML 比数据库模式更具层次性,关系性更弱,因此我认为树形视图更能体现模式的结构。
该编辑器已通过使用它来创建 XML Schema Primer 中使用的 Purchase Order XSD 进行了测试[^]。特点
- 动态调整全局和局部类型
- 动态创建元素中的复杂类型
- 选择树节点会高亮显示对应的 XML 文本
- 编译器错误窗口
- 自动为元素和属性选择“ref”或“type”
- XML 可直接编辑,而非使用树形结构
- 在添加和删除类型时,创建并管理全局类型列表
- 键盘快捷键
- F2 - 编辑节点标签
- Ctrl-A:在当前节点下添加到 Schema
- Ctrl-T:转到 Schema 顶部
- Ctrl-P:转到当前节点的父节点
Schema Object Model 的部分实现
SOM 是一个复杂且庞大的系统,它实现了一组对应于万维网联盟 (W3C) XML Schema 推荐的类。XSD 编辑器使用 SOM 实现以下 Schema 类型(图片来自 MSDN SOM 层级文档)XmlSchemaFacet 和 XmlSchemaNumericFacet 类
XmlSchemaType 类
XmlSchemaObject 类,除了 XmlSchemaAnnotated
XmlSchemaSimpleTypeRestriction 在 XmlSchemaSimpleTypeContent 类中
XmlSchemaAttribute 类
这些类提供了设计 XSD 文档的基本功能。SOM 中还有许多其他类,目前该编辑器不支持。我将根据需要添加对这些附加类的支持。
用法
使用方法很简单。加载 Schema
在空白的 Schema 中,使用“文件/打开”命令加载 Schema。编辑 Schema
通过右键单击树节点来添加和删除 Schema 树中的节点。弹出菜单提供了可以添加的不同 Schema 元素。请注意,此菜单不是根据允许的 Schema 类型为选定节点上下文敏感的。添加的任何 Schema 元素都默认为“xs:string”类型。选择类型
编辑器会自动跟踪全局 Schema 元素。要更改 Schema 元素,请在 Schema 树中选择所需的元素,然后从简单类型组合框或全局类型组合框中选择所需的类型。如果适用,编辑器将自动进行必要的更改以使用引用,反之亦然,如果元素应该是类型。查看源代码行
编辑器会自动高亮显示树节点在 Schema 中对应的行。如果此功能不起作用,请从菜单中选择“Schema/Compile”以同步 Schema 与树。直接编辑 Schema
Schema 可以在 Schema 编辑框中直接编辑。请记住在进行更改后编译 Schema。如果这样做,您将丢失所做的更改,如果您随后使用树形结构操作 Schema。使用 SOM
我发现使用 .NET 的 SOM 并非易事。它不是一个通用的分层类模型。Schema 元素包含在 Schema 对象不同成员的集合中。例如,XmlSchemaComplexType
的属性包含在 Attribute
成员中,而子元素包含在 XmlSchemaSequence
对象中,该对象是分配给 Particle
成员的对象。此外,给定一个 Schema 对象,无法确定其父 Schema 元素。所有这些都使得插入和删除 Schema 对象需要一些复杂的规则。编辑器中的 Remove
函数说明了这一点
// 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!请注意,我从树视图中获取父级,而不是从 Schema 中获取!
我使用树视图的图像来确定父级类型!
Schema 根对象被简单地移除
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; }Schema 注释对象从
XmlSchemaAnnotation
Items
成员中移除// 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; }如果父级是
XmlSchemaSimpleType
,那么我必须根据对象类型(XmlSchemaAnnotation
或 XmlSchemaFacet
)从不同的地方移除该对象// 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; }父级不能是
XmlSchemaElement
,因为任何带有子元素的元素都是 XmlSchemaComplexType
,它包含 XmlSchemaAttribute
或 XmlSchemaElement
对象作为 XmlSchemaSequence
Items
集合的一部分。// 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; } } } ... }正如您所见,这并不简单。
怪癖
1. 在编辑节点 B 的同时单击节点 A 会导致节点 A 的名称被更改(鼠标按下事件处理程序设置了当前节点!)2. 在文本编辑框中编辑 Schema 后,您必须编译,否则更改将丢失!
3. 如果树节点与 Schema 对象不匹配,XSD 文件中会出现空白行导致同步问题。请选择菜单中的“Schema/Compile”。
缺失的功能
1. 自动滚动编辑框以显示选定节点2. 编译 Schema 时记住选定的节点
3. 实现 XmlSchemaElement 的 minOccurs 和 maxOccurs,并提供 GUI 输入值
4. 实现 XmlSchemaAttribute 的 fixed 并提供 GUI 输入值
5. 实现 XmlSchemaGroup
6. 其他?
结论
我发现编写这个编辑器是理解 XSD 文档细节的一个绝佳方式。对于好奇的读者,这个编辑器大约需要 40 小时的工作量!历史
2003 年 1 月 21 日 - 首次发布2003 年 10 月 15 日 - 添加了对更复杂 Schema 的支持,修复了一些小 bug。