Search code examples
c#xmldeserialization

Deserializing XML element with attributes into list of strings


I have an XML

  <dependency ref="pkg:maven/org.keycloak/keycloak-services@10.0.2?type=jar">
        <dependency ref="pkg:maven/com.sun.mail/jakarta.mail@1.6.4?type=jar"/>
        <dependency ref="pkg:maven/org.glassfish/jakarta.json@1.1.6?type=jar"/>
        <dependency ref="pkg:maven/org.jboss.spec.javax.servlet/jboss-servlet-api_4.0_spec@2.0.0.Final?type=jar"/>
        <dependency ref="pkg:maven/org.twitter4j/twitter4j-core@4.0.7?type=jar"/>
        <dependency ref="pkg:maven/org.jboss.logging/jboss-logging@3.4.1.Final?type=jar"/>
        <dependency ref="pkg:maven/org.jboss.spec.javax.ws.rs/jboss-jaxrs-api_2.1_spec@2.0.1.Final?type=jar"/>
        <dependency ref="pkg:maven/org.jboss.spec.javax.transaction/jboss-transaction-api_1.3_spec@2.0.0.Final?type=jar"/>
        <dependency ref="pkg:maven/org.jboss.resteasy/resteasy-multipart-provider@3.11.2.Final?type=jar"/>
        <dependency ref="pkg:maven/com.googlecode.owasp-java-html-sanitizer/owasp-java-html-sanitizer@20191001.1?type=jar"/>
        <dependency ref="pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.10.1?type=jar"/>
        <dependency ref="pkg:maven/com.openshift/openshift-restclient-java@8.0.0.Final?type=jar"/>
        <dependency ref="pkg:maven/com.webauthn4j/webauthn4j-core@0.10.2.RELEASE?type=jar"/>
    </dependency>

I am not sure how to deserialize this XML as the model shown below using System.Xml.Serialization in c#

     [XmlType(TypeName = "dependency")]
     public class Dependency
     {

        public Dependency()
        {
            this.DependsOn = new List<string>();
        }

        [XmlAttribute("ref")]
        [JsonProperty("ref")]
        public string Ref { get; set; } = string.Empty;

        [XmlArray("dependency")]
        [XmlAttribute("ref")]
        [JsonProperty("dependsOn")]
        public List<string> DependsOn { get; set; }
}

I am using this model, because I would like to use the same model for both JSON and XML deserialization

The JSON sample looks like this

"dependency": {
      "ref": "pkg:maven/org.jboss.resteasy/resteasy-jaxrs@3.11.2.Final?type=jar",
      "dependsOn": [
        "pkg:maven/org.jboss.spec.javax.ws.rs/jboss-jaxrs-api_2.1_spec@2.0.1.Final?type=jar",
        "pkg:maven/org.jboss.spec.javax.xml.bind/jboss-jaxb-api_2.3_spec@2.0.0.Final?type=jar",
        "pkg:maven/org.reactivestreams/reactive-streams@1.0.3?type=jar",
        "pkg:maven/jakarta.validation/jakarta.validation-api@2.0.2?type=jar",
        "pkg:maven/org.jboss.spec.javax.annotation/jboss-annotations-api_1.3_spec@2.0.1.Final?type=jar",
        "pkg:maven/com.sun.activation/jakarta.activation@1.2.1?type=jar",
        "pkg:maven/commons-io/commons-io@2.6?type=jar",
        "pkg:maven/com.github.stephenc.jcip/jcip-annotations@1.0-1?type=jar"
      ]
    }
}

I tried the above, but I am getting an error Xml attribute cannot be used in conjunction with XmlArray, Could someone please help me with this scenario


Solution

  • There are many ways to solve your problem.
    XmlSerializer is very flexible. The simplest way is to subscribe to the Unknown* event. And in its handler, manually implement the receipt and saving of the necessary data.

    Full code example:

    using System.Xml.Serialization;
    using Newtonsoft.Json;
    
    using var fs = new FileStream("test.xml", FileMode.Open);
    var ser = new XmlSerializer(typeof(Dependency));
    ser.UnknownElement += Serializer_UnknownElement;
    
    var dependency = (Dependency)ser.Deserialize(fs);
    
    Console.WriteLine(dependency.Ref);
    Console.WriteLine(dependency.DependsOn.Count);
    foreach (var value in dependency.DependsOn)
        Console.WriteLine(value);
    
    Console.WriteLine();
    var json = JsonConvert.SerializeObject(dependency, Formatting.Indented);
    Console.WriteLine(json);
    
    void Serializer_UnknownElement(object? sender, XmlElementEventArgs e)
    {
        if (e.Element.Name == "dependency")
        {
            var refAttr = e.Element.Attributes["ref"];
            if (refAttr != null)
            {
                var dependency = (Dependency)e.ObjectBeingDeserialized;
                dependency.DependsOn.Add(refAttr.Value);
            }
        }
    }
    
    [XmlType(TypeName = "dependency")]
    public class Dependency
    {
        public Dependency() => this.DependsOn = new List<string>();
    
        [XmlAttribute("ref")]
        [JsonProperty("ref")]
        public string Ref { get; set; } = string.Empty;
    
        [JsonProperty("dependsOn")]
        public List<string> DependsOn { get; }
    }
    

    XML deserialization works fine.

    Note that serialization to JSON does not give the result you want.