Десериализовать XML с несколькими пространствами имен VARYING?

Я пытаюсь десериализовать отчеты XML. Это класс, который создается из XML (с классом все в порядке). Однако пространства имен различаются в зависимости от версии SQL-сервера.

например пространство имен отчета, которое

"http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition"

в приведенном ниже примере также может быть

"http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition"

и т.п.

Также я предполагаю, что это пространство имен может отличаться

"http://schemas.microsoft.com/SQLServer/reporting/reportdesigner"

Как я могу десериализовать XML с различным пространством имен (без создания отдельного класса для каждого возможного пространства имен)?

Это мой XML-класс:

using System.Xml.Serialization;
using System.Collections.Generic;


namespace Xml2CSharp 
{
   [XmlRoot(ElementName = "DataSource",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DataSource
   {
       [XmlElement(ElementName = "DataSourceReference",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string DataSourceReference { get; set; }

       [XmlElement(ElementName = "SecurityType",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string SecurityType { get; set; }

       [XmlElement(ElementName = "DataSourceID",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string DataSourceID { get; set; }

       [XmlAttribute(AttributeName = "Name")]
       public string Name { get; set; }
   }

   [XmlRoot(ElementName = "DataSources",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DataSources
   {
       [XmlElement(ElementName = "DataSource",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DataSource DataSource { get; set; }
   }

   [XmlRoot(ElementName = "QueryParameter",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class QueryParameter
   {
       [XmlElement(ElementName = "Value",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Value { get; set; }

       [XmlAttribute(AttributeName = "Name")]
       public string Name { get; set; }
   }

   [XmlRoot(ElementName = "QueryParameters",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class QueryParameters
   {
       [XmlElement(ElementName = "QueryParameter",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public List<QueryParameter> QueryParameter { get; set; }
   }

   [XmlRoot(ElementName = "Query",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class Query
   {
       [XmlElement(ElementName = "DataSourceName",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string DataSourceName { get; set; }

       [XmlElement(ElementName = "QueryParameters",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public QueryParameters QueryParameters { get; set; }

       [XmlElement(ElementName = "CommandType",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string CommandType { get; set; }

       [XmlElement(ElementName = "CommandText",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string CommandText { get; set; }

       [XmlElement(ElementName = "Timeout",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Timeout { get; set; }

       [XmlElement(ElementName = "UseGenericDesigner",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string UseGenericDesigner { get; set; }
   }

   [XmlRoot(ElementName = "Field",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class Field
   {
       [XmlElement(ElementName = "DataField",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string DataField { get; set; }

       [XmlElement(ElementName = "TypeName",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string TypeName { get; set; }

       [XmlAttribute(AttributeName = "Name")]
       public string Name { get; set; }
   }

   [XmlRoot(ElementName = "Fields",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class Fields
   {
       [XmlElement(ElementName = "Field",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public List<Field> Field { get; set; }
   }

   [XmlRoot(ElementName = "DataSet",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DataSet
   {
       [XmlElement(ElementName = "Query",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public Query Query { get; set; }

       [XmlElement(ElementName = "Fields",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public Fields Fields { get; set; }

       [XmlAttribute(AttributeName = "Name")]
       public string Name { get; set; }
   }

   [XmlRoot(ElementName = "DataSets",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DataSets
   {
       [XmlElement(ElementName = "DataSet",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public List<DataSet> DataSet { get; set; }
   }

   [XmlRoot(ElementName = "Values",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class Values
   {
       [XmlElement(ElementName = "Value",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Value { get; set; }
   }

   [XmlRoot(ElementName = "DefaultValue",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DefaultValue
   {
       [XmlElement(ElementName = "Values",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public Values Values { get; set; }

       [XmlElement(ElementName = "DataSetReference",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DataSetReference DataSetReference { get; set; }
   }

   [XmlRoot(ElementName = "ReportParameter",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class ReportParameter
   {
       [XmlElement(ElementName = "DataType",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string DataType { get; set; }

       [XmlElement(ElementName = "DefaultValue",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DefaultValue DefaultValue { get; set; }

       [XmlElement(ElementName = "Prompt",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Prompt { get; set; }

       [XmlElement(ElementName = "Hidden",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Hidden { get; set; }

       [XmlAttribute(AttributeName = "Name")]
       public string Name { get; set; }

       [XmlElement(ElementName = "ValidValues",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public ValidValues ValidValues { get; set; }
   }

   [XmlRoot(ElementName = "DataSetReference",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class DataSetReference
   {
       [XmlElement(ElementName = "DataSetName",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string DataSetName { get; set; }

       [XmlElement(ElementName = "ValueField",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string ValueField { get; set; }

       [XmlElement(ElementName = "LabelField",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string LabelField { get; set; }
   }

   [XmlRoot(ElementName = "ValidValues",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class ValidValues
   {
       [XmlElement(ElementName = "DataSetReference",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DataSetReference DataSetReference { get; set; }
   }

   [XmlRoot(ElementName = "ReportParameters",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class ReportParameters
   {
       [XmlElement(ElementName = "ReportParameter",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public List<ReportParameter> ReportParameter { get; set; }
   }

   [XmlRoot(ElementName = "Report",
       Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
   public class Report
   {
       [XmlElement(ElementName = "AutoRefresh",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string AutoRefresh { get; set; }

       [XmlElement(ElementName = "DataSources",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DataSources DataSources { get; set; }

       [XmlElement(ElementName = "DataSets",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public DataSets DataSets { get; set; }

       [XmlElement(ElementName = "ReportParameters",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public ReportParameters ReportParameters { get; set; }

       [XmlElement(ElementName = "Code",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Code { get; set; }

       [XmlElement(ElementName = "Language",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string Language { get; set; }

       [XmlElement(ElementName = "ConsumeContainerWhitespace",
           Namespace = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")]
       public string ConsumeContainerWhitespace { get; set; }

       [XmlElement(ElementName = "ReportUnitType",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string ReportUnitType { get; set; }

       [XmlElement(ElementName = "ReportID",
           Namespace = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
       public string ReportID { get; set; }

       [XmlAttribute(AttributeName = "xmlns")]
       public string Xmlns { get; set; }

       [XmlAttribute(AttributeName = "rd", Namespace = "http://www.w3.org/2000/xmlns/")]
       public string Rd { get; set; }
   }
}

person Community    schedule 28.02.2018    source источник
comment
Не используйте сериализацию. Обычно я использую Xml Linq, который позволяет динамически извлекать пространство имен из элементов.   -  person jdweng    schedule 28.02.2018
comment
@jdweng: Нет, тогда мне нужно разбирать элементы вручную, чего я и пытаюсь избежать.   -  person    schedule 28.02.2018
comment
Решение Стефана должно быть установлено во время компиляции, в то время как мое решение является динамическим и будет работать с любым URL.   -  person jdweng    schedule 28.02.2018
comment
@jdweng: Во-первых, я использую десериализацию, а не сериализацию. Кроме того, продолжается дальнейшая обработка - а переключение формата не является ни простым, ни тривиальным - поэтому результат нужно десериализовать - я не хочу сам разбирать его. Xml Linq не заменяет десериализацию.   -  person    schedule 19.03.2018


Ответы (1)


Как насчет чтения пространства имен, затем замены его в тексте, а затем десериализации из замененного текста?
Поскольку у вас есть отчет, шансы, что текст пространства имен появится где-то в содержимом, должны быть маловероятными ...

public RdlReader OpenXml(string xml)
{
    System.Xml.XmlDocument document = new System.Xml.XmlDocument();
    document.XmlResolver = null;
    document.PreserveWhitespace = true;
    document.LoadXml(xml);

    string default_namespace = Xml2CSharp.Report.DEFAULT_NAMESPACE;
    string designer_namespace = Xml2CSharp.Report.DESIGNER_NAMESPACE;

    if (document.DocumentElement.HasAttribute("xmlns"))
        default_namespace = document.DocumentElement.Attributes["xmlns"].Value;

    if (document.DocumentElement.HasAttribute("xmlns:rd"))
        designer_namespace = document.DocumentElement.Attributes["xmlns:rd"].Value;

    this.m_xml = xml
        .Replace(default_namespace, Xml2CSharp.Report.DEFAULT_NAMESPACE)
        .Replace(designer_namespace, Xml2CSharp.Report.DESIGNER_NAMESPACE);

    document = null;


    document = new System.Xml.XmlDocument();
    document.XmlResolver = null;
    document.PreserveWhitespace = true;
    document.LoadXml(this.m_xml);


    Xml2CSharp.Report rep = Tools.XML.Serialization.DeserializeXmlFromString<Xml2CSharp.Report>(this.m_xml);
    System.Console.WriteLine(rep);

    this.m_document = document;
    this.m_nsmgr = GetReportNamespaceManager(this.m_document);

    return this;
}

Нравится:

[XmlRoot(ElementName = "Report",
    Namespace = Report.DEFAULT_NAMESPACE)]
public class Report
{
    public const string DEFAULT_NAMESPACE = "http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition";
    public const string DESIGNER_NAMESPACE = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
    [...]
person Stefan Steiger    schedule 28.02.2018
comment
Это решение не динамическое. Он должен быть установлен во время компиляции. - person jdweng; 28.02.2018
comment
@jdweng: Неправильно, потому что он динамически заменяет 2 пространства имен В СТРОКЕ XML на скомпилированное пространство имен по умолчанию, которое является постоянным (не динамическим) - это работает во время выполнения - это не функция времени компиляции. Но это хитрость - это обращение проблемы - создание пространств имен XML такими же, как у сериализатора. - person Stefan Steiger; 28.02.2018
comment
Мне кажется, что свойство класса не изменяется во время выполнения: Namespace = Report.DEFAULT_NAMESPACE - person jdweng; 28.02.2018
comment
@jdweng: Да, свойство не меняется. Но XML изменяется, чтобы соответствовать скомпилированным свойствам: this.m_xml = xml .Replace (default_namespace, Xml2CSharp.Report.DEFAULT_NAMESPACE) .Replace (designer_namespace, Xml2CSharp.Report.DESIGNER_NAMESPACE); вот почему это работает. - person Stefan Steiger; 28.02.2018