I'm writing a class to serialize a KiCAD BOM/Schematic file. The class works fine and correctly serialize and deserialize the original file but I'm having two small problems that I'm unable to fix. This's the class code:
[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;
}
}
The first issue is on the XmlRoot
element for SchematicExport
. I expected version
attribute to appear inside the root XML tag but it does not:
<export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
The second issue is the order of elements (OK it's not a big issue since tags are not order dependent) I tried to use XmlElement(Order=nn)
attribute to force it but I just got a number of Reflection
exceptions.
I just managed to remove xmlns:xsi
and xmlns:xsd
with a minor modification in serializer:
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);
}
}
I found another (more malicious) issue, even if I can deserialize such 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>
The resulting serialization is not complete:
<?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>
As you can see <datasheet>
tags are missing (comp sections) as also <description>
(libpart sections).
I cannot really understand where's the mistake, but apparently the problem is not a in deserialization: