【问题标题】:Create xsd schema from instance of class at runtime在运行时从类的实例创建 xsd 架构
【发布时间】:2019-09-19 09:19:21
【问题描述】:

我需要验证一些通用传感器输入。要求是,验证不能在我的代码中进行,而是使用来自代码库外部的外部验证器(如 xsd),使用户能够交换验证逻辑而无需编码或重新编译应用程序。 我知道传感器输入仅对一种特定情况有效,因此希望从运行时存在且经过用户验证的类的实例生成 xsd,以获得有效的限制。

我尝试了来自this 问题的想法,但这仅适用于类型而不适用于类的实例。

因此我的问题是:有没有办法获取 C# 类的运行时实例并将其转换为将属性值作为唯一有效限制的 xsd?

更新:

澄清:我所拥有的是这样的课程:

public sealed class Sensor
    {
        public int Data { get; set; }

        public int otherData { get; set; }

        public int MoreData { get; set; }
    }

该类在某处被实例化(例如,像这样):

var se = new Sensor()
            {
                Data = 5,
                otherData = 10,
                MoreData = 15
            };

当我现在尝试使用以下函数创建 xsd 时:

var schemas = new XmlSchemas();
var exporter = new XmlSchemaExporter(schemas);
var mapping = new XmlReflectionImporter().ImportTypeMapping(typeof(Person));
exporter.ExportTypeMapping(mapping);
var schemaWriter = new StringWriter();
foreach (XmlSchema schema in schemas)
{
    schema.Write(schemaWriter);
}
return schemaWriter.ToString();

我收到一些像这样的 xsd:

<?xml version="1.0" encoding="utf-8"?>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="sensor">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="Data" type="xs:integer" />
            <xs:element name="otherData" type="xs:integer" />
            <xs:element name="moreData" type="xs:integer" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>

但这远不是我想要的。我想在其中内置适当的限制(它应该看起来像这样):

<?xml version="1.0" encoding="utf-8"?>
        <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
          <xs:element name="sensor">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="Data">
                    <xs:simpleType>
                        <xs:restriction base="xs:integer">
                            <xs:enumeration value="5"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
                <xs:element name="otherData">
                    <xs:simpleType>
                        <xs:restriction base="xs:integer">
                            <xs:enumeration value="10"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
                <xs:element name="moreData">
                    <xs:simpleType>
                        <xs:restriction base="xs:integer">
                            <xs:enumeration value="15"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:schema>

我显然可以继续将生成的文件加载到内存中,去除一些属性并更改 xsd 的外观,但这感觉不对,因为以下原因:

  1. 由我来定义 xsd 应该如何看起来像我带走的规则 我希望拥有的灵活性。
  2. 这种方法对我来说似乎很容易出错,因为它似乎基本上比直接字符串操作要好一些。
  3. 这个额外的代码会使我已经很大的代码变得更复杂和更难理解。

总结一下:我需要一个库或一个非常聪明的函数,它可以根据我在课堂上的 runitme 信息创建一个像上面那样的 xsd,而无需编写很多东西直接操作 xml 以避免对验证的未来使用容易出错或错误假设。

【问题讨论】:

  • xsd 是 xml 格式,因此您可以使用任何 xml 写入库创建架构。
  • 您是否有一个让这一切变得简单的库?我真的不希望通过手动编码来生成 xsd 的复杂性。
  • 有两个步骤 1) 枚举类的属性(参见:stackoverflow.com/questions/737151/…) 2)然后通过从步骤 1 获取属性来创建 xml/xsd。
  • @jdweng 请参阅我的更新以进行澄清。感谢您的帮助

标签: c# xsd runtime xsd-validation


【解决方案1】:

我采用了您的生成架构并使用 Xml Linq 添加了详细信息。见下方代码

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.IO;

namespace ConsoleApplication131
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            Sensor se = new Sensor()
            {
                Data = 5,
                otherData = 10,
                MoreData = 15
            };

            XmlSchemas schemas = new XmlSchemas();
            XmlSchemaExporter exporter = new XmlSchemaExporter(schemas);
            XmlTypeMapping mapping = new XmlReflectionImporter().ImportTypeMapping(typeof(Sensor));
            exporter.ExportTypeMapping(mapping);
            StringWriter schemaWriter = new StringWriter();
            foreach (XmlSchema schema in schemas)
            {
                schema.Write(schemaWriter);
            }
            XDocument doc = XDocument.Parse(schemaWriter.ToString());
            XElement root = doc.Root;
            XNamespace xs = root.GetNamespaceOfPrefix("xs");

            foreach (XElement _class in doc.Descendants(xs + "complexType"))
            {
                List<XElement> elements = _class.Descendants(xs + "element").ToList();
                if (elements.Count > 0)
                {
                    XElement complexType = new XElement(xs + "complexType");
                    _class.Add(complexType);
                    XElement sequence = new XElement(xs + "sequence");
                    complexType.Add(sequence);

                    foreach (var prop in se.GetType().GetProperties())
                    {
                        string name = prop.Name;
                        string value = prop.GetValue(se, null).ToString();
                        XElement element = elements.Where(x => (string)x.Attribute("name") == name).FirstOrDefault();
                        string strType = (string)element.Attribute("type");

                        XElement newElement = new XElement(xs + "simpleType", new object[] {
                        new XElement(xs + "restriction", new object[] {
                            new XAttribute("base", strType),
                            new XElement(xs + "enumeration", new XAttribute("value", value))
                        })
                    });
                        sequence.Add(newElement);

                    }
                }
            }
            doc.Save(FILENAME);

        }
    }
    public sealed class Sensor
    {
        public int Data { get; set; }
        public int otherData { get; set; }
        public int MoreData { get; set; }
    }

}

【讨论】:

  • 感谢您的实施。我会在星期一回到办公室时检查它。据我所知,它看起来不错,而且没有我担心的那么大。
  • 那是因为我从现有的架构开始,刚刚添加了元素。它可能需要更改。我只是试图让它尽可能接近你的帖子。
猜你喜欢
  • 2019-05-14
  • 2011-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
相关资源
最近更新 更多