Home > Net >  Preserve Xml Xsd schemaLocation when deserializing then serializing
Preserve Xml Xsd schemaLocation when deserializing then serializing

Time:10-13

I am deserializing an Xml file into a .NET class, modifying properties, then serializing back into the same file. This is the .NET model (vb.net)

<XmlRoot("StationSetpoints")>
Public Class XmlStationSetpoints
    <XmlElement("Setpoint")>
    Public Property Setpoints As List(Of XmlStationSetpointsSetpoint)
End Class

<Serializable>
Public Class XmlStationSetpointsSetpoint
    <XmlElement("Point")>
    Public Property Points As List(Of XmlStationSetpointsSetpointPoint)
    ' etc...
End Class

Deserialization and serialization (c#)

var settings = New XmlStationSetpoints();
var serializer = New XmlSerializer(XmlStationSetpoints);
// deserialize
using StreamReader sr = new StreamReader(path)
    settings = (XmlStationSetpoints)serializer.Deserialize(sr);
// serialize
using StreamWriter sw = new StreamWriter(path, false)
    serializer.Serialize(sw, settings);

The original Xml file, including my local schema file which resides next to the Xml file xsi:schemaLocation="http://www.w3schools.com StationSetpoints.xsd" (line 5)

<?xml version="1.0" encoding="utf-8"?>
<StationSetpoints
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xsi:schemaLocation="http://www.w3schools.com StationSetpoints.xsd">
  <Setpoint PartNumber="108022">
    <Point InstrumentName="PD Stage" Value="10"/>
  </Setpoint>
  <Setpoint PartNumber="107983">
    <Point Order="2" InstrumentName="PD Stage" Value="7.5"/>
  </Setpoint>
</StationSetpoints>

When the file is serialized, that schema path is not included

<?xml version="1.0" encoding="utf-8"?>
<StationSetpoints 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Setpoint PartNumber="108022">
    <Point Order="0" InstrumentName="PD Stage" Value="10"></Point>
  </Setpoint>
  <Setpoint PartNumber="107983">
    <Point Order="2" InstrumentName="PD Stage" Value="7.5"></Point>
  </Setpoint>
</StationSetpoints>

How can I preserve that schema path in the .NET class, so that the serialized file includes it?

CodePudding user response:

You can deserialize and re-serialize the xsi:schemaLocation attribute by adding an explicit property for that purpose, as shown in this answer by dtb to XmlSerialization and xsi:SchemaLocation (xsd.exe), suitably translated to VB.NET:

Public Partial Class XmlStationSetpoints
    <XmlAttribute("schemaLocation", Namespace:="http://www.w3.org/2001/XMLSchema-instance")>
    Public Property xsiSchemaLocation As String = "http://www.w3schools.com StationSetpoints.xsd"
End Class

Demo fiddle #1 here.

If you would like to hardcode the value of xsi:schemaLocation and have it appear unconditionally when serializing, you may do so with an explicitly implemented property like so:

Public Partial Class XmlStationSetpoints
    <XmlAttribute("schemaLocation", Namespace:="http://www.w3.org/2001/XMLSchema-instance")>
    Public Property xsiSchemaLocation() As String
        Get
            Return "http://www.w3schools.com StationSetpoints.xsd"
        End Get
        Set
            ' Do nothing, it's hardcoded.  A setter is required because XmlSerializer will only serialize properties with public getters and setters.
        End Set
    End Property
End Class

Demo fiddle #2 here.

And if you would like to hardcode the value of xsi:schemaLocation but control whether or not it appears (because e.g. it should only appear when XmlStationSetpoints is the root element of the XML file) you may do so with an xsiSchemaLocationSpecified property like so:

Public Partial Class XmlStationSetpoints
    <XmlAttribute("schemaLocation", Namespace:="http://www.w3.org/2001/XMLSchema-instance")>
    Public Property xsiSchemaLocation() As String
        Get
            Return "http://www.w3schools.com StationSetpoints.xsd"
        End Get
        Set
            ' Do nothing, it's hardcoded.  A setter is required because XmlSerializer will only serialize properties with public getters and setters.
        End Set
    End Property
    <XmlIgnore>
    Public Property xsiSchemaLocationSpecified() As Boolean
End Class

The property will capture whether the xsi:schemaLocation property was encountered during deserialization, and will control whether the property is emitted during serialization.

Demo fiddle #3 here.

  • Related