Создать схему xsd из экземпляра класса во время выполнения - PullRequest
0 голосов
/ 19 сентября 2019

Мне нужно проверить какой-то общий вход датчика.Требование заключается в том, что проверка не может происходить в моем коде, но с помощью внешнего средства проверки, такого как xsd, за пределами кодовой базы, чтобы дать пользователям возможность менять логику проверки без необходимости кодировать или перекомпилировать приложение.Я знаю, что вход датчика действителен только для одного конкретного случая и поэтому хотел бы сгенерировать xsd из экземпляра класса, который существует во время выполнения, который был проверен пользователем, чтобы получить действительные ограничения.

Я попробовал идею из этого вопроса, однако это работает только для типов, а не для экземпляров классов.

Поэтому мой вопрос: есть ли способ взять экземпляр времени выполнения класса 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. Этот дополнительный код сделает мой и без того большой код более сложным и трудным для понимания.

Подводя итог: Мне нужна либо библиотека, либо действительно умная функция, которая может создать xsd, подобный приведенному выше, на основе информации о runitme, которая есть у меня в классе, без записи.много вещей, чтобы манипулировать XML напрямую, чтобы избежать ошибок или ошибочных предположений о будущем использовании проверки.

1 Ответ

0 голосов
/ 19 сентября 2019

Я взял вашу схему генерации и добавил детали, используя 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; }
    }

}
...