Xml 排序和 XMLRoot 属性中的序列化问题
Xml Serialization Issues in Ordering and XMLRoot attributes
我正在编写 class 来序列化 KiCAD BOM/Schematic 文件。 class 工作正常并正确序列化和反序列化原始文件,但我有两个小问题无法修复。
这是 class 代码:
[XmlRoot(ElementName = "export")]
public class SchematicExport
{
[XmlAttribute]
public const string version = "D";
public Design design { get; set; }
[XmlArrayItem(typeof(Component), ElementName = "comp")]
public List<Component> components;
[XmlArrayItem(typeof(LibPart), ElementName = "libpart")]
public List<LibPart> libparts;
[XmlArrayItem(typeof(Library), ElementName = "library")]
public List<Library> libraries;
[XmlArrayItem(typeof(Net), ElementName = "net")]
public List<Net> nets;
public class Design
{
public string source { get; set; }
public string date
{
get => _date.ToString("dd/MM/yyyy HH:mm:ss");
set => _date = DateTime.Parse(value);
}
private DateTime _date;
public string tool { get; set; }
[XmlElement("sheet")]
public List<Sheet> sheets { get; }
public class Sheet
{
[XmlAttribute]
public int number { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string tstamps { get; set; }
public TitleBlock title_block { get; set; }
public class TitleBlock
{
public string title { get; set; }
public string company { get; set; }
public string rev { get; set; }
public string date
{
get => _date.ToString("yyyy-MM-dd");
set => _date = DateTime.Parse(value);
}
private DateTime _date;
public string source { get; set; }
[XmlElement("comment")]
public List<Comment> comments;
public class Comment
{
[XmlAttribute]
public int number;
[XmlAttribute]
public string value;
public Comment()
{
}
public Comment(int number, string value) : this()
{
this.number = number;
this.value = value;
}
}
public TitleBlock()
{
comments = new List<Comment>();
_date = DateTime.Now;
}
public TitleBlock(string title, string company, string rev, string date, string source)
{
this.title = title;
this.company = company;
this.rev = rev;
this.date = date;
this.source = source;
}
}
public Sheet()
{
title_block = new TitleBlock();
tstamps = DateTime.Now.ToFileTime().ToString("X8");
}
public Sheet(int number, string name) : this()
{
this.number = number;
this.name = name;
}
}
public Design()
{
sheets = new List<Sheet>();
_date = DateTime.Now;
}
public Design(string source, string date, string tool) : this()
{
this.source = source;
this.date = date;
this.tool = tool;
}
}
public class Component
{
[XmlAttribute("ref")]
public string reference { get; set; }
public string value { get; set; }
public string footprint { get; set; }
public string datasheet { get; set; }
[XmlArrayItem(typeof(Field), ElementName = "field")]
public List<Field> fields;
public LibSource libsource { get; set; }
public SheetPath sheetpath { get; set; }
public string tstamp { get; set; }
public class LibSource
{
[XmlAttribute]
public string lib { get; set; }
[XmlAttribute]
public string part { get; set; }
[XmlAttribute]
public string description { get; set; }
}
public class SheetPath
{
[XmlAttribute]
public string names { get; set; }
[XmlAttribute]
public string tstamps { get; set; }
}
public Component()
{
fields = new List<Field>();
libsource = new LibSource();
sheetpath = new SheetPath();
tstamp = DateTime.Now.ToFileTime().ToString("X8");
}
public Component(string reference, string value, string footprint) : this()
{
this.reference = reference;
this.value = value;
this.footprint = footprint;
}
}
public class LibPart
{
[XmlAttribute]
public string lib { get; set; }
[XmlAttribute]
public string part { get; set; }
[XmlArrayItem(typeof(Field), ElementName = "field")]
public List<Field> fields;
[XmlArrayItem(typeof(string), ElementName = "fp")]
public List<string> footprints;
[XmlArrayItem(typeof(Pin), ElementName = "pin")]
public List<Pin> pins;
public class Pin
{
[XmlAttribute]
public string num { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string type { get; set; }
public Pin()
{
}
public Pin(string num, string name, string type) : this()
{
this.num = num;
this.name = name;
this.type = type;
}
}
public LibPart()
{
fields = new List<Field>();
footprints = new List<string>();
pins = new List<Pin>();
}
public LibPart(string lib, string part) : this()
{
this.lib = lib;
this.part = part;
}
}
public class Library
{
[XmlAttribute]
public string logical { get; set; }
public string uri { get; set; }
public Library() { }
public Library(string logical, string uri) : this()
{
this.logical = logical;
this.uri = uri;
}
}
public class Net
{
[XmlAttribute]
public string code { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlElement("node")]
public List<Node> nodes;
public class Node
{
[XmlAttribute("ref")]
public string reference { get; set; }
[XmlAttribute]
public string pin { get; set; }
public Node() { }
public Node(string reference, string pin) : this()
{
this.reference = reference;
this.pin = pin;
}
}
public Net()
{
nodes = new List<Node>();
}
public Net(string code, string name) : this()
{
this.code = code;
this.name = name;
}
}
public class Field
{
[XmlAttribute]
public string name { get; set; }
[XmlText]
public string value { get; set; }
public Field()
{
}
public Field(string name, string value) : this()
{
this.name = name;
this.value = value;
}
}
public SchematicExport()
{
design = new Design();
components = new List<Component>();
libparts = new List<LibPart>();
libraries = new List<Library>();
nets = new List<Net>();
}
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
TextWriter _textWriter = new StreamWriter(filename);
_xmlSerializer.Serialize(_textWriter, this);
}
public static SchematicExport Create(string filename)
{
if (!System.IO.File.Exists(filename))
throw new Exception("File not existing");
SchematicExport _schematicExport = null;
XmlSerializer _serializer = new XmlSerializer(typeof(SchematicExport));
StreamReader _reader = new StreamReader(filename);
_schematicExport = (SchematicExport)_serializer.Deserialize(_reader);
return _schematicExport;
}
}
第一个问题是关于 SchematicExport
的 XmlRoot
元素。我希望 version
属性出现在根 XML 标记内,但它没有:
<export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
第二个问题是元素的顺序(好的,这不是一个大问题,因为标签不依赖于顺序)我尝试使用 XmlElement(Order=nn)
属性来强制它,但我只得到了一些 Reflection
异常。
我刚刚通过在序列化程序中稍作修改来删除 xmlns:xsi
和 xmlns:xsd
:
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
XmlSerializerNamespaces _serializerNamespaces = new XmlSerializerNamespaces();
_serializerNamespaces.Add("", "");
using (TextWriter _textWriter = new StreamWriter(filename))
{
_xmlSerializer.Serialize(_textWriter, this, _serializerNamespaces);
}
}
我发现了另一个(更恶意的)问题,即使我可以反序列化这样的 Xml:
?xml version="1.0" encoding="UTF-8"?>
<export version="D">
<design>
<source>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119\V1-10A119.sch</source>
<date>07/03/2019 10:33:01</date>
<tool>Eeschema (5.0.2)-1</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
<title>V1-10A119</title>
<company>ROB.INT. s.r.l.</company>
<rev>01</rev>
<date>2019-02-25</date>
<source>V1-10A119.sch</source>
<comment number="1" value="Michele Santucci"/>
<comment number="2" value=""/>
<comment number="3" value=""/>
<comment number="4" value=""/>
</title_block>
</sheet>
</design>
<components>
<comp ref="U5">
<value>ADM3101E</value>
<footprint>Analog:LFCSP-12_EP_3x3_Pitch0.5mm</footprint>
<datasheet>https://www.analog.com/media/en/technical-documentation/data-sheets/adm3101e.pdf</datasheet>
<fields>
<field name="Code">820-9369 </field>
<field name="P/N">ADM3101EACPZ-250R7 </field>
<field name="Productor">Analog</field>
<field name="Provider">RS</field>
<field name="manf#">ADM3101EACPZ-250R7 </field>
</fields>
<libsource lib="V1-10A119-rescue" part="ADM3101E-analog" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C83E717</tstamp>
</comp>
<comp ref="C35">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AA07</tstamp>
</comp>
<comp ref="C37">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB0B</tstamp>
</comp>
<comp ref="C34">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB65</tstamp>
</comp>
<comp ref="C38">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AC22</tstamp>
</comp>
<comp ref="C36">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84D1BA</tstamp>
</comp>
</components>
<libparts>
<libpart lib="conn" part="CONN_2">
<description>Symbole general de connecteur</description>
<fields>
<field name="Reference">P</field>
<field name="Value">CONN_2</field>
</fields>
<pins>
<pin num="1" name="P1" type="passive"/>
<pin num="2" name="PM" type="passive"/>
</pins>
</libpart>
</libparts>
<libraries>
<library logical="V1-10A119-rescue">
<uri>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119/V1-10A119-rescue.lib</uri>
</library>
<library logical="conn">
<uri>C:/Users/Public/Documents/Kicad/library/conn.lib</uri>
</library>
</libraries>
<nets>
<net code="200" name="VBUS">
<node ref="P9" pin="2"/>
<node ref="U3" pin="3"/>
<node ref="C12" pin="2"/>
<node ref="C30" pin="2"/>
<node ref="U4" pin="3"/>
</net>
<net code="201" name="Net-(LD13-Pad1)">
<node ref="LD13" pin="1"/>
<node ref="R37" pin="1"/>
</net>
</nets>
</export>
生成的序列化不完整:
<?xml version="1.0" encoding="UTF-8"?>
<export version="D">
<design>
<source>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119\V1-10A119.sch</source>
<date>07/03/2019 10:33:01</date>
<tool>Eeschema (5.0.2)-1</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
<title>V1-10A119</title>
<company>ROB.INT. s.r.l.</company>
<rev>01</rev>
<date>2019-02-25</date>
<source>V1-10A119.sch</source>
<comment number="1" value="Michele Santucci"/>
<comment number="2" value=""/>
<comment number="3" value=""/>
<comment number="4" value=""/>
</title_block>
</sheet>
</design>
<components>
<comp ref="U5">
<value>ADM3101E</value>
<footprint>Analog:LFCSP-12_EP_3x3_Pitch0.5mm</footprint>
<fields>
<field name="Code">820-9369 </field>
<field name="P/N">ADM3101EACPZ-250R7 </field>
<field name="Productor">Analog</field>
<field name="Provider">RS</field>
<field name="manf#">ADM3101EACPZ-250R7 </field>
</fields>
<libsource lib="V1-10A119-rescue" part="ADM3101E-analog" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C83E717</tstamp>
</comp>
<comp ref="C35">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AA07</tstamp>
</comp>
<comp ref="C37">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB0B</tstamp>
</comp>
<comp ref="C34">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB65</tstamp>
</comp>
<comp ref="C38">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AC22</tstamp>
</comp>
<comp ref="C36">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84D1BA</tstamp>
</comp>
</components>
<libparts>
<libpart lib="conn" part="CONN_2">
<fields>
<field name="Reference">P</field>
<field name="Value">CONN_2</field>
</fields>
<pins>
<pin num="1" name="P1" type="passive"/>
<pin num="2" name="PM" type="passive"/>
</pins>
</libpart>
</libparts>
<libraries>
<library logical="V1-10A119-rescue">
<uri>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119/V1-10A119-rescue.lib</uri>
</library>
<library logical="conn">
<uri>C:/Users/Public/Documents/Kicad/library/conn.lib</uri>
</library>
</libraries>
<nets>
<net code="200" name="VBUS">
<node ref="P9" pin="2"/>
<node ref="U3" pin="3"/>
<node ref="C12" pin="2"/>
<node ref="C30" pin="2"/>
<node ref="U4" pin="3"/>
</net>
<net code="201" name="Net-(LD13-Pad1)">
<node ref="LD13" pin="1"/>
<node ref="R37" pin="1"/>
</net>
</nets>
</export>
如您所见,缺少 <datasheet>
标签(comp 部分)以及 <description>
(libpart 部分)。
我真的不明白哪里出了问题,但显然问题不在反序列化中:
第一期是关于XmlRoot
元素的。我希望 version
属性出现在 XMLRoot
标签内,但它没有。
如 Introducing XML Serialization 中所述,即使在 public:[=37 时,XmlSerializer
也不会序列化 const
成员=]
XML serialization serializes only the public fields and property values of an object into an XML stream. XML serialization does not include type information.
<snip>
XML serialization does not convert methods, indexers, private fields, or read-only properties (except read-only collections). To serialize all an object's fields and properties, both public and private, use the DataContractSerializer instead of XML serialization.
解决此问题的最简单方法是为版本添加一个替代项 属性,如下所示:
public const string version = "D";
[XmlAttribute("version")]
[System.ComponentModel.Browsable(false), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string Version { get { return version; } set { /* Do nothing */ } }
属性 必须是 public,但您可以通过属性 Browsable
, EditorBrowsable
and DebuggerBrowsable
.
降低其可见性
第二个问题是元素的顺序(好吧,这不是什么大问题,因为标签不依赖于顺序)我尝试使用 XmlElement(Order=nn)
属性来强制它,但我只是得到了一个Reflection
个异常数。
您没有提供这方面的示例,但我能够重现以下问题。如果我在 some 而不是 SchematicExport
的集合成员的 all 上设置 XmlArrayAttribute.Order
,我会得到以下异常:
System.InvalidOperationException: There was an error reflecting type 'SchematicExport'.
---> System.InvalidOperationException: Inconsistent sequencing: if used on one of the class's members, the 'Order' property is required on all particle-like members, please explicitly set 'Order' using XmlElement, XmlAnyElement or XmlArray custom attribute on class member 'nets'.
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
演示 fiddle #1 here.
解决方案是遵循异常消息中的建议,将 order 属性应用于 class 中的所有可序列化成员。
因此 SchematicExport
应该类似于:
[XmlRoot(ElementName = "export")]
public partial class SchematicExport
{
public const string version = "D";
[XmlAttribute("version")]
[System.ComponentModel.Browsable(false), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string Version { get { return version; } set { /* Do nothing */ } }
[XmlElement(Order = 1)]
public Design design { get; set; }
[XmlArray(Order = 2)]
[XmlArrayItem(typeof(Component), ElementName = "comp")]
public List<Component> components;
[XmlArray(Order = 3)]
[XmlArrayItem(typeof(LibPart), ElementName = "libpart")]
public List<LibPart> libparts;
[XmlArray(Order = 4)]
[XmlArrayItem(typeof(Library), ElementName = "library")]
public List<Library> libraries;
[XmlArray(Order = 5)]
[XmlArrayItem(typeof(Net), ElementName = "net")]
public List<Net> nets;
}
请注意,设置元素顺序不仅会在序列化期间对元素重新排序,而且要求它们在反序列化期间按该顺序排列。
顺便说一句,在 SchematicExport.Serialize(string)
中,您需要关闭 StreamWriter
。最简单的方法是通过 using
语句:
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
// FIXED ensure the file is closed.
using (var _textWriter = new StreamWriter(filename))
{
_xmlSerializer.Serialize(_textWriter, this);
}
}
您问题中显示的此方法的第一个版本不会执行此操作。
演示 fiddle #2 here.
我正在编写 class 来序列化 KiCAD BOM/Schematic 文件。 class 工作正常并正确序列化和反序列化原始文件,但我有两个小问题无法修复。 这是 class 代码:
[XmlRoot(ElementName = "export")]
public class SchematicExport
{
[XmlAttribute]
public const string version = "D";
public Design design { get; set; }
[XmlArrayItem(typeof(Component), ElementName = "comp")]
public List<Component> components;
[XmlArrayItem(typeof(LibPart), ElementName = "libpart")]
public List<LibPart> libparts;
[XmlArrayItem(typeof(Library), ElementName = "library")]
public List<Library> libraries;
[XmlArrayItem(typeof(Net), ElementName = "net")]
public List<Net> nets;
public class Design
{
public string source { get; set; }
public string date
{
get => _date.ToString("dd/MM/yyyy HH:mm:ss");
set => _date = DateTime.Parse(value);
}
private DateTime _date;
public string tool { get; set; }
[XmlElement("sheet")]
public List<Sheet> sheets { get; }
public class Sheet
{
[XmlAttribute]
public int number { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string tstamps { get; set; }
public TitleBlock title_block { get; set; }
public class TitleBlock
{
public string title { get; set; }
public string company { get; set; }
public string rev { get; set; }
public string date
{
get => _date.ToString("yyyy-MM-dd");
set => _date = DateTime.Parse(value);
}
private DateTime _date;
public string source { get; set; }
[XmlElement("comment")]
public List<Comment> comments;
public class Comment
{
[XmlAttribute]
public int number;
[XmlAttribute]
public string value;
public Comment()
{
}
public Comment(int number, string value) : this()
{
this.number = number;
this.value = value;
}
}
public TitleBlock()
{
comments = new List<Comment>();
_date = DateTime.Now;
}
public TitleBlock(string title, string company, string rev, string date, string source)
{
this.title = title;
this.company = company;
this.rev = rev;
this.date = date;
this.source = source;
}
}
public Sheet()
{
title_block = new TitleBlock();
tstamps = DateTime.Now.ToFileTime().ToString("X8");
}
public Sheet(int number, string name) : this()
{
this.number = number;
this.name = name;
}
}
public Design()
{
sheets = new List<Sheet>();
_date = DateTime.Now;
}
public Design(string source, string date, string tool) : this()
{
this.source = source;
this.date = date;
this.tool = tool;
}
}
public class Component
{
[XmlAttribute("ref")]
public string reference { get; set; }
public string value { get; set; }
public string footprint { get; set; }
public string datasheet { get; set; }
[XmlArrayItem(typeof(Field), ElementName = "field")]
public List<Field> fields;
public LibSource libsource { get; set; }
public SheetPath sheetpath { get; set; }
public string tstamp { get; set; }
public class LibSource
{
[XmlAttribute]
public string lib { get; set; }
[XmlAttribute]
public string part { get; set; }
[XmlAttribute]
public string description { get; set; }
}
public class SheetPath
{
[XmlAttribute]
public string names { get; set; }
[XmlAttribute]
public string tstamps { get; set; }
}
public Component()
{
fields = new List<Field>();
libsource = new LibSource();
sheetpath = new SheetPath();
tstamp = DateTime.Now.ToFileTime().ToString("X8");
}
public Component(string reference, string value, string footprint) : this()
{
this.reference = reference;
this.value = value;
this.footprint = footprint;
}
}
public class LibPart
{
[XmlAttribute]
public string lib { get; set; }
[XmlAttribute]
public string part { get; set; }
[XmlArrayItem(typeof(Field), ElementName = "field")]
public List<Field> fields;
[XmlArrayItem(typeof(string), ElementName = "fp")]
public List<string> footprints;
[XmlArrayItem(typeof(Pin), ElementName = "pin")]
public List<Pin> pins;
public class Pin
{
[XmlAttribute]
public string num { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string type { get; set; }
public Pin()
{
}
public Pin(string num, string name, string type) : this()
{
this.num = num;
this.name = name;
this.type = type;
}
}
public LibPart()
{
fields = new List<Field>();
footprints = new List<string>();
pins = new List<Pin>();
}
public LibPart(string lib, string part) : this()
{
this.lib = lib;
this.part = part;
}
}
public class Library
{
[XmlAttribute]
public string logical { get; set; }
public string uri { get; set; }
public Library() { }
public Library(string logical, string uri) : this()
{
this.logical = logical;
this.uri = uri;
}
}
public class Net
{
[XmlAttribute]
public string code { get; set; }
[XmlAttribute]
public string name { get; set; }
[XmlElement("node")]
public List<Node> nodes;
public class Node
{
[XmlAttribute("ref")]
public string reference { get; set; }
[XmlAttribute]
public string pin { get; set; }
public Node() { }
public Node(string reference, string pin) : this()
{
this.reference = reference;
this.pin = pin;
}
}
public Net()
{
nodes = new List<Node>();
}
public Net(string code, string name) : this()
{
this.code = code;
this.name = name;
}
}
public class Field
{
[XmlAttribute]
public string name { get; set; }
[XmlText]
public string value { get; set; }
public Field()
{
}
public Field(string name, string value) : this()
{
this.name = name;
this.value = value;
}
}
public SchematicExport()
{
design = new Design();
components = new List<Component>();
libparts = new List<LibPart>();
libraries = new List<Library>();
nets = new List<Net>();
}
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
TextWriter _textWriter = new StreamWriter(filename);
_xmlSerializer.Serialize(_textWriter, this);
}
public static SchematicExport Create(string filename)
{
if (!System.IO.File.Exists(filename))
throw new Exception("File not existing");
SchematicExport _schematicExport = null;
XmlSerializer _serializer = new XmlSerializer(typeof(SchematicExport));
StreamReader _reader = new StreamReader(filename);
_schematicExport = (SchematicExport)_serializer.Deserialize(_reader);
return _schematicExport;
}
}
第一个问题是关于 SchematicExport
的 XmlRoot
元素。我希望 version
属性出现在根 XML 标记内,但它没有:
<export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
第二个问题是元素的顺序(好的,这不是一个大问题,因为标签不依赖于顺序)我尝试使用 XmlElement(Order=nn)
属性来强制它,但我只得到了一些 Reflection
异常。
我刚刚通过在序列化程序中稍作修改来删除 xmlns:xsi
和 xmlns:xsd
:
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
XmlSerializerNamespaces _serializerNamespaces = new XmlSerializerNamespaces();
_serializerNamespaces.Add("", "");
using (TextWriter _textWriter = new StreamWriter(filename))
{
_xmlSerializer.Serialize(_textWriter, this, _serializerNamespaces);
}
}
我发现了另一个(更恶意的)问题,即使我可以反序列化这样的 Xml:
?xml version="1.0" encoding="UTF-8"?>
<export version="D">
<design>
<source>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119\V1-10A119.sch</source>
<date>07/03/2019 10:33:01</date>
<tool>Eeschema (5.0.2)-1</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
<title>V1-10A119</title>
<company>ROB.INT. s.r.l.</company>
<rev>01</rev>
<date>2019-02-25</date>
<source>V1-10A119.sch</source>
<comment number="1" value="Michele Santucci"/>
<comment number="2" value=""/>
<comment number="3" value=""/>
<comment number="4" value=""/>
</title_block>
</sheet>
</design>
<components>
<comp ref="U5">
<value>ADM3101E</value>
<footprint>Analog:LFCSP-12_EP_3x3_Pitch0.5mm</footprint>
<datasheet>https://www.analog.com/media/en/technical-documentation/data-sheets/adm3101e.pdf</datasheet>
<fields>
<field name="Code">820-9369 </field>
<field name="P/N">ADM3101EACPZ-250R7 </field>
<field name="Productor">Analog</field>
<field name="Provider">RS</field>
<field name="manf#">ADM3101EACPZ-250R7 </field>
</fields>
<libsource lib="V1-10A119-rescue" part="ADM3101E-analog" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C83E717</tstamp>
</comp>
<comp ref="C35">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AA07</tstamp>
</comp>
<comp ref="C37">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB0B</tstamp>
</comp>
<comp ref="C34">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB65</tstamp>
</comp>
<comp ref="C38">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AC22</tstamp>
</comp>
<comp ref="C36">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<datasheet>~</datasheet>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84D1BA</tstamp>
</comp>
</components>
<libparts>
<libpart lib="conn" part="CONN_2">
<description>Symbole general de connecteur</description>
<fields>
<field name="Reference">P</field>
<field name="Value">CONN_2</field>
</fields>
<pins>
<pin num="1" name="P1" type="passive"/>
<pin num="2" name="PM" type="passive"/>
</pins>
</libpart>
</libparts>
<libraries>
<library logical="V1-10A119-rescue">
<uri>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119/V1-10A119-rescue.lib</uri>
</library>
<library logical="conn">
<uri>C:/Users/Public/Documents/Kicad/library/conn.lib</uri>
</library>
</libraries>
<nets>
<net code="200" name="VBUS">
<node ref="P9" pin="2"/>
<node ref="U3" pin="3"/>
<node ref="C12" pin="2"/>
<node ref="C30" pin="2"/>
<node ref="U4" pin="3"/>
</net>
<net code="201" name="Net-(LD13-Pad1)">
<node ref="LD13" pin="1"/>
<node ref="R37" pin="1"/>
</net>
</nets>
</export>
生成的序列化不完整:
<?xml version="1.0" encoding="UTF-8"?>
<export version="D">
<design>
<source>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119\V1-10A119.sch</source>
<date>07/03/2019 10:33:01</date>
<tool>Eeschema (5.0.2)-1</tool>
<sheet number="1" name="/" tstamps="/">
<title_block>
<title>V1-10A119</title>
<company>ROB.INT. s.r.l.</company>
<rev>01</rev>
<date>2019-02-25</date>
<source>V1-10A119.sch</source>
<comment number="1" value="Michele Santucci"/>
<comment number="2" value=""/>
<comment number="3" value=""/>
<comment number="4" value=""/>
</title_block>
</sheet>
</design>
<components>
<comp ref="U5">
<value>ADM3101E</value>
<footprint>Analog:LFCSP-12_EP_3x3_Pitch0.5mm</footprint>
<fields>
<field name="Code">820-9369 </field>
<field name="P/N">ADM3101EACPZ-250R7 </field>
<field name="Productor">Analog</field>
<field name="Provider">RS</field>
<field name="manf#">ADM3101EACPZ-250R7 </field>
</fields>
<libsource lib="V1-10A119-rescue" part="ADM3101E-analog" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C83E717</tstamp>
</comp>
<comp ref="C35">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AA07</tstamp>
</comp>
<comp ref="C37">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB0B</tstamp>
</comp>
<comp ref="C34">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AB65</tstamp>
</comp>
<comp ref="C38">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84AC22</tstamp>
</comp>
<comp ref="C36">
<value>100nF</value>
<footprint>Capacitors_SMD:C_0603</footprint>
<fields>
<field name="Code">135-8345 </field>
<field name="P/N">06035G104ZAT2A</field>
<field name="Productor">AVX</field>
<field name="Provider">RS</field>
<field name="manf#">06035G104ZAT2A</field>
</fields>
<libsource lib="V1-10A119-rescue" part="C_Small-Device" description=""/>
<sheetpath names="/MICRO/" tstamps="/5D2A20EE/"/>
<tstamp>5C84D1BA</tstamp>
</comp>
</components>
<libparts>
<libpart lib="conn" part="CONN_2">
<fields>
<field name="Reference">P</field>
<field name="Value">CONN_2</field>
</fields>
<pins>
<pin num="1" name="P1" type="passive"/>
<pin num="2" name="PM" type="passive"/>
</pins>
</libpart>
</libparts>
<libraries>
<library logical="V1-10A119-rescue">
<uri>C:\Users\m.santucci\Documents\Progetti\Viper\Schede Viper\V1-10A119/V1-10A119-rescue.lib</uri>
</library>
<library logical="conn">
<uri>C:/Users/Public/Documents/Kicad/library/conn.lib</uri>
</library>
</libraries>
<nets>
<net code="200" name="VBUS">
<node ref="P9" pin="2"/>
<node ref="U3" pin="3"/>
<node ref="C12" pin="2"/>
<node ref="C30" pin="2"/>
<node ref="U4" pin="3"/>
</net>
<net code="201" name="Net-(LD13-Pad1)">
<node ref="LD13" pin="1"/>
<node ref="R37" pin="1"/>
</net>
</nets>
</export>
如您所见,缺少 <datasheet>
标签(comp 部分)以及 <description>
(libpart 部分)。
我真的不明白哪里出了问题,但显然问题不在反序列化中:
第一期是关于XmlRoot
元素的。我希望 version
属性出现在 XMLRoot
标签内,但它没有。
如 Introducing XML Serialization 中所述,即使在 public:[=37 时,XmlSerializer
也不会序列化 const
成员=]
XML serialization serializes only the public fields and property values of an object into an XML stream. XML serialization does not include type information.
<snip>
XML serialization does not convert methods, indexers, private fields, or read-only properties (except read-only collections). To serialize all an object's fields and properties, both public and private, use the DataContractSerializer instead of XML serialization.
解决此问题的最简单方法是为版本添加一个替代项 属性,如下所示:
public const string version = "D";
[XmlAttribute("version")]
[System.ComponentModel.Browsable(false), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string Version { get { return version; } set { /* Do nothing */ } }
属性 必须是 public,但您可以通过属性 Browsable
, EditorBrowsable
and DebuggerBrowsable
.
第二个问题是元素的顺序(好吧,这不是什么大问题,因为标签不依赖于顺序)我尝试使用 XmlElement(Order=nn)
属性来强制它,但我只是得到了一个Reflection
个异常数。
您没有提供这方面的示例,但我能够重现以下问题。如果我在 some 而不是 SchematicExport
的集合成员的 all 上设置 XmlArrayAttribute.Order
,我会得到以下异常:
System.InvalidOperationException: There was an error reflecting type 'SchematicExport'.
---> System.InvalidOperationException: Inconsistent sequencing: if used on one of the class's members, the 'Order' property is required on all particle-like members, please explicitly set 'Order' using XmlElement, XmlAnyElement or XmlArray custom attribute on class member 'nets'.
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
演示 fiddle #1 here.
解决方案是遵循异常消息中的建议,将 order 属性应用于 class 中的所有可序列化成员。
因此 SchematicExport
应该类似于:
[XmlRoot(ElementName = "export")]
public partial class SchematicExport
{
public const string version = "D";
[XmlAttribute("version")]
[System.ComponentModel.Browsable(false), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string Version { get { return version; } set { /* Do nothing */ } }
[XmlElement(Order = 1)]
public Design design { get; set; }
[XmlArray(Order = 2)]
[XmlArrayItem(typeof(Component), ElementName = "comp")]
public List<Component> components;
[XmlArray(Order = 3)]
[XmlArrayItem(typeof(LibPart), ElementName = "libpart")]
public List<LibPart> libparts;
[XmlArray(Order = 4)]
[XmlArrayItem(typeof(Library), ElementName = "library")]
public List<Library> libraries;
[XmlArray(Order = 5)]
[XmlArrayItem(typeof(Net), ElementName = "net")]
public List<Net> nets;
}
请注意,设置元素顺序不仅会在序列化期间对元素重新排序,而且要求它们在反序列化期间按该顺序排列。
顺便说一句,在 SchematicExport.Serialize(string)
中,您需要关闭 StreamWriter
。最简单的方法是通过 using
语句:
public void Serialze(string filename)
{
XmlSerializer _xmlSerializer = new XmlSerializer(typeof(SchematicExport));
// FIXED ensure the file is closed.
using (var _textWriter = new StreamWriter(filename))
{
_xmlSerializer.Serialize(_textWriter, this);
}
}
您问题中显示的此方法的第一个版本不会执行此操作。
演示 fiddle #2 here.