Генерация XSLT-файла из XSD на основе соответствия XSD с отображением 1: 1 XML in -> XSD-совместимости XML out - PullRequest
0 голосов
/ 10 января 2020

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

1002 * У меня есть довольно сложный XSD-файл (также набор из XSD файлы, для каждой версии схемы).
В конечном итоге я ищу набор файлов XSLT, который может взять файл XML, совместимый с XSD v12, и преобразовывать его (отбрасывать много материала) до тех пор, пока становится XSD v3-совместимым XML файлом. Возможно, что некоторые из преобразований будут немного умнее, как, например, взятие градиентаStartColor и присвоение его backgroundFillColor, если градиентМод = "3" ... но я не ищу, чтобы эта часть выполнялась автоматически.

Таким образом, мой Шаг 1 будет следующим: создать XSLT-файл, который «соответствует» XSD-файлу, так что совместимый со схемой файл XML проходит через нетронутым. Но там, где файл, несовместимый со схемой XML, содержит все эти несовместимые атрибуты / элементы. Я бы даже не заботился о проверке значений.

Я ожидал, что найдется способ автоматически сгенерировать такой XSLT-файл. Но мой поиск в Google не дал результатов.

Я понимаю, что XSLT изначально не поддерживает схемы (по крайней мере, в XSLT 1), но я ожидаю, что некоторое автоматическое c создание шаблона XSLT может перечислите через XSD, чтобы добавить «привязку», достаточную для эмуляции схемы.
Или я заблуждаюсь в этой мысли?

Спасибо

Ответы [ 2 ]

0 голосов
/ 11 января 2020

Хорошо, значит, решение было неким. NET code.

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using Microsoft.CSharp;

namespace Reverter
{
    class Program
    {
        static int Main(string[] args)
        {
            //try
            {
                if (args.Length < 2)
                {
                    Console.Error.WriteLine("Reverter schema.xsd inputfile1 inputfile2...");
                    return 1;
                }
                else
                {
                    var schema = args[0];
                    List<string> srcFiles = new List<string>(args);
                    srcFiles.RemoveAt(0); // we get rid of the first entry, the schema


                    XmlSchemas xsds = new XmlSchemas();
                    XmlSchema xsd;
                    using (var r = File.OpenText(schema))
                    {
                        xsd = XmlSchema.Read(r, null);
                        xsds.Add(xsd);
                    }

                    xsds.Compile(null, true);

                    XmlSchemaImporter schemaImporter = new XmlSchemaImporter(xsds);

                    // create the codedom
                    CodeNamespace codeNamespace = new CodeNamespace("Schema");
                    XmlCodeExporter codeExporter = new XmlCodeExporter(codeNamespace);

                    List<XmlTypeMapping> maps = new List<XmlTypeMapping>();

                    foreach (XmlSchemaElement schemaElement in xsd.Elements.Values)
                    {
                        maps.Add(schemaImporter.ImportTypeMapping(schemaElement.QualifiedName));
                    }

                    foreach (XmlSchemaType schemaElement in xsd.Items.OfType<XmlSchemaType>())
                    {
                        maps.Add(schemaImporter.ImportSchemaType(schemaElement.QualifiedName));
                    }

                    foreach (XmlTypeMapping map in maps)
                    {
                        codeExporter.ExportTypeMapping(map);
                    }

                    codeNamespace.Types.OfType<CodeTypeDeclaration>().First(x => x.Name == "ROOTELEMENTNAME").Members.Add(
                        new CodeMemberProperty()
                        {
                            Name = "xsiSchemaLocation",
                            Attributes = MemberAttributes.Public | MemberAttributes.Final,
                            CustomAttributes =
                            {
                                new CodeAttributeDeclaration("System.Xml.Serialization.XmlAttribute",
                                    new CodeAttributeArgument[]
                                    {
                                        new CodeAttributeArgument(new CodePrimitiveExpression("noNamespaceSchemaLocation")),
                                        new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(XmlSchema.InstanceNamespace)),
                                    }
                                )
                            },
                            Type = new CodeTypeReference(typeof(string)),
                            HasGet = true,
                            GetStatements =
                            {
                                new CodeMethodReturnStatement(new CodePrimitiveExpression(schema))
                            },
                            HasSet = true,
                        });

                    // Check for invalid characters in identifiers
                    CodeGenerator.ValidateIdentifiers(codeNamespace);

                    CodeCompileUnit ccu = new CodeCompileUnit();
                    ccu.Namespaces.Add(codeNamespace);

                    CompilerParameters comParams = new CompilerParameters(
                        new string[] { "System.dll", "System.Xml.dll" } );
                    comParams.GenerateInMemory = true;
                    comParams.CompilerOptions = "/optimize";

                    CodeGeneratorOptions codeOptions = new CodeGeneratorOptions();
                    codeOptions.VerbatimOrder = true;

                    TextWriter memText = new StringWriter();

                    // output the C# code
                    CodeDomProvider codeProvider = new CSharpCodeProvider();
                    var codeResult = codeProvider.CompileAssemblyFromDom(comParams, new CodeCompileUnit[] { ccu });

                    XmlSerializer ser = new XmlSerializer(codeResult.CompiledAssembly.GetType("Schema.ROOTELEMENTTYPE", true, true));
                    Object obj;

                    XmlWriterSettings xmlSettings = new XmlWriterSettings();
                    xmlSettings.Indent = true;
                    xmlSettings.Encoding = System.Text.Encoding.UTF8;
                    xmlSettings.OmitXmlDeclaration = false;


                    foreach (string srcFile in srcFiles)
                    {
                        var dstFile = "New" + srcFile;
                        // using our XmlSerializer, we will load and then save the XMLfile
                        using (var file = new XmlTextReader(srcFile))
                        using(var outFile = XmlWriter.Create(dstFile, xmlSettings))
                        {
                            obj = ser.Deserialize(file);
                            ser.Serialize(outFile, obj);
                        }
                    }
                }
            }
            /*catch (Exception ex)
            {
                Console.Error.WriteLine("Revert code generation failed.");
                Console.Error.Write(ex.ToString());
                return 2;
            }*/

            return 0;
        }
    }
}

Практически просто возьмите файл XSD в качестве входных данных для механизма CodeDom, сгенерируйте скомпилированную сборку, захватите тип root из новой сборки, затем десериализовать и повторно сериализовать объекты. Если вам нужна некоторая консольная печать для того, что было выброшено, вы можете генерировать обратные вызовы для событий UnknownElement, UnknownAttribute или UnknownNode в XmlDeserializer.

0 голосов
/ 10 января 2020

Это довольно сложная попытка, и меня не удивляет, что никто этого не сделал. Люди написали кандидатские диссертации по небольшим частям проблемы, например, взяли две грамматики (модели контента) и выяснили, является ли одна из них подмножеством другой.

И, несомненно, есть сопоставления, которые вы не можете автоматизировать: тогда как удалить элементы, которые больше не разрешены, достаточно просто, добавить элементы, которые стали обязательными, или переименовать те, чье имя изменилось, или обновить те, чей тип изменился, будет довольно сложно.

Если вы ограничиваете ваши амбиции в нескольких простых случаях, вы могли бы добиться прогресса. Но я бы сосредоточился на том, чтобы сделать его полезным для вашего конкретного случая использования, а не сделать его универсальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...