65.9K
CodeProject 正在变化。 阅读更多。
Home

XML 架构定义(XSD) 编辑器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (81投票s)

2003 年 1 月 21 日

5分钟阅读

viewsIcon

420079

downloadIcon

11119

一个能够生成常见 XSD 文档的编辑器

Sample Image - XSDEditor.jpg

目录

引言

本文介绍了一个 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,那么我必须根据对象类型(XmlSchemaAnnotationXmlSchemaFacet)从不同的地方移除该对象
      // 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,它包含 XmlSchemaAttributeXmlSchemaElement 对象作为 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。
© . All rights reserved.