0

I have a problem with creating the appropriate class to deserialize the xml file. The xml structure looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" target-language="pl" datatype="plaintext" original="1112">
        <body>
            <group id="90362">
                <trans-unit id="90362::aff_11">
                    <source>text 1 1</source>
                    <target>text 1 1</target>
                </trans-unit>
                <trans-unit id="90362::aff_12">
                    <source>text 1 2</source>
                    <target>text 1 2</target>
                </trans-unit>
                <trans-unit id="90362::aff_13">
                    <source>text 1 3</source>
                    <target>text 1 3</target>
                </trans-unit>
            </group>
            <group id="90392">
                <trans-unit id="90392::aff_21">
                    <source>text 2 1</source>
                    <target>text 2 1</target>
                </trans-unit>
                <trans-unit id="90392::aff_22">
                    <source>text 2 2</source>
                    <target>text 2 2</target>
                </trans-unit>
                <trans-unit id="90392::aff_23">
                    <source>text 2 3</source>
                    <target>text 2 3</target>
                </trans-unit>    
            </group>  
        </body>
    </file>
</xliff>

As you can see, we have nested arrays within arrays. In addition, one of the arrays has a name that cannot be given the same name for the class. Pre-created classes:

[XmlRoot("xliff", Namespace = "urn:oasis:names:tc:xliff:document:1.2")]
    public class xliff
    {
        public file file { get; set; }
    }

    public class file
    {
        public body body { get; set; }
    }

    public class body : List<group>
    {        
        public List<group> groups { get; set; }
    }

    public class group //: List<trans>
    {        
        public List<trans> trans { get; set; }
    }
        
    public class trans 
    {
        [XmlElement("source")]
        public string source { get; set; }
        [XmlElement("target")]
        public string target { get; set; }
    } 

Unfortunately, I have a problem to complete classes to get to source and target values.

aszejda
  • 17
  • 4
  • `I have a problem to complete classes to get to and values.` what problem? Apart from trying to use the deprecated 1.2 format instead of the current 2.x. How did you generate the classes? I see that the [XSD for XLIFF 1.2](http://docs.oasis-open.org/xliff/v1.2/os/xliff-core.html#AppDTD) is available so you should be able to generate classes using `xsd.exe` or `svcutil.exe`, or an open source class generation tool – Panagiotis Kanavos Jan 19 '22 at 09:43
  • 1
    [you should not inherit from `List`](https://stackoverflow.com/questions/21692193/why-not-inherit-from-listt). Instead chose composition over inheritance, which means your `body`-class **has** a collection of groups, in contrast to your `body`-class **being** such a collection – MakePeaceGreatAgain Jan 19 '22 at 09:43
  • 2
    When creating XmlSerializer types for deserialization, it's often easiest to try *serializing* your classes to see what the output is, and keep tweaking them until the structure of the output XML matches what you expect. Then you know they will correctly deserialize your input – canton7 Jan 19 '22 at 09:47
  • The Net library for arrays/list defaults to two layers of tags Where the parent is defined with [XmlArray("parent")] and the child is defined with [XmlArrayItem("child")]. When the Xml has only one tag you must add [XmlElement{"child")] to change default to only one tag. – jdweng Jan 19 '22 at 10:01
  • @canton7 XLIFF has a large XSD schema. It's impractical to try to create the classes by hand – Panagiotis Kanavos Jan 19 '22 at 10:02
  • 1
    @PanagiotisKanavos Why is that directed at me? Obviously if you only want to parse a subset of XLIFF (as OP wants to do - they're even ignoring attributes), writing a small number of classes by hand is perfectly viable. Otherwise, xsd.exe and XmlSchemaClassGenerator are your friends, of course – canton7 Jan 19 '22 at 10:58

3 Answers3

2

you should not inherit from List<T>. Instead chose composition over inheritance, which means your body-class has a collection of groups, in contrast to your body-class being such a collection.

So you may use this structure instead:

[XmlRoot("xliff", Namespace = "urn:oasis:names:tc:xliff:document:1.2")]
public class xliff
{
    public file file { get; set; }
}

public class file
{
    public body body { get; set; }
}

public class body
{        
    [XmlElement("group")]
    public List<group> groups { get; set; }
}

public class group
{        
    [XmlElement("trans")]
    public List<trans> trans { get; set; }
}
    
public class trans 
{
    [XmlElement("source")]
    public string source { get; set; }
    [XmlElement("target")]
    public string target { get; set; }
} 

Furthermore you should consider to use PascalCase for your classes. To give those classes different names within the serialized xml, you may use the xml-attributes, e.g.:

[XmlRott("body")]
public class Body
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • XLIFF is defined by a schema that's far more complex than 5-6 elements. The file generated by `xsd.exe` is over 1000 lines – Panagiotis Kanavos Jan 19 '22 at 09:58
  • 1
    @PanagiotisKanavos true, but that has no relevance to the actual problem, IMHO. All the other elements aren't part of the above xml, so this simple class-structure would be sufficiectn for it. That the xsd defines more classes also, doesn't mean we need them. – MakePeaceGreatAgain Jan 19 '22 at 10:01
  • I doubt that's the actual document. XLIFF is used to store localization data so any practical document will contain more than that sample. It's not practical to create the classes by hand. Looking at [an XLIFF sample from SAP](https://help.sap.com/viewer/ed6ce7a29bdd42169f5f0d7868bce6eb/Cloud/en-US/4848857040fe44f3b224e65594a0ab9e.html) I see a lot of missing info, even once you remove the SAP extensions. – Panagiotis Kanavos Jan 19 '22 at 10:10
  • 1
    @PanagiotisKanavos The lovely thing about XmlSerializer is that you can just define classes for the bits of the schema you're interested in, and everything else gets ignored by the deserializer. If you're only interested in part of a file, you don't have to deserialize the whole thing! – canton7 Jan 19 '22 at 11:05
2

You can use an online tool to convert XML to c# model: https://json2csharp.com/xml-to-csharp

Try to use this model (generated by above tool):

// using System.Xml.Serialization;
// XmlSerializer serializer = new XmlSerializer(typeof(Xliff));
// using (StringReader reader = new StringReader(xml))
// {
//    var test = (Xliff)serializer.Deserialize(reader);
// }

[XmlRoot(ElementName="trans-unit")]
public class Transunit { 

    [XmlElement(ElementName="source")] 
    public string Source { get; set; } 

    [XmlElement(ElementName="target")] 
    public string Target { get; set; } 

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

    [XmlText] 
    public string Text { get; set; } 
}

[XmlRoot(ElementName="group")]
public class Group { 

    [XmlElement(ElementName="transunit")] 
    public List<Transunit> Transunit { get; set; } 

    [XmlAttribute(AttributeName="id")] 
    public int Id { get; set; } 

    [XmlText] 
    public string Text { get; set; } 
}

[XmlRoot(ElementName="body")]
public class Body { 

    [XmlElement(ElementName="group")] 
    public List<Group> Group { get; set; } 
}

[XmlRoot(ElementName="file")]
public class File { 

    [XmlElement(ElementName="body")] 
    public Body Body { get; set; } 

    [XmlAttribute(AttributeName="source-language")] 
    public string SourceLanguage { get; set; } 

    [XmlAttribute(AttributeName="target-language")] 
    public string TargetLanguage { get; set; } 

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

    [XmlAttribute(AttributeName="original")] 
    public int Original { get; set; } 

    [XmlText] 
    public string Text { get; set; } 
}

[XmlRoot(ElementName="xliff")]
public class Xliff { 

    [XmlElement(ElementName="file")] 
    public File File { get; set; } 

    [XmlAttribute(AttributeName="version")] 
    public DateTime Version { get; set; } 

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

    [XmlText] 
    public string Text { get; set; } 
}
SeeSharp
  • 1,730
  • 11
  • 31
1

XLIFF is far more complex and has far more elements than this. The current version is 2.1 but the older 1.2 is also described in the OASIS site, along with links to the XSD schema

Almost all standardized XML documents are based on an XML schema, available as an XSD document (XML Schema Definition).

You can use the xsd.exe tool to generate C# classes from the XSD file. You can download eg http://docs.oasis-open.org/xliff/v1.2/cs02/xliff-core-1.2-strict.xsd locally as xliff.xsd and then execute

xsd xliff.xsd /c 

To generate the file xliff.cs with all the classes.

The result is over 1000 lines so it can't just be pasted here.

The tree structure, copied from the docs, has a lot of elements :


<xliff>1
| |
| +--- [Extension Point]
| |
+--- <file>+
 |
 +--- <header>?
 | |
 | +--- <skl>?
 | | |
 | | +--- (<internal-file> | <external-file>)1
 | |
 | +--- <phase-group>?
 | | |
 | | +--- <phase>+
 | | |
 | | +--- <note>*
 | |
 | +--- <glossary>*
 | | |
 | | +--- (<internal-file> | <external-file>)1
 | |
 | +--- <reference>*
 | | |
 | | +--- (<internal-file> | <external-file>)1
 | |
 | +--- <count-group>*
 | | |
 | | +--- <count>*
 | |
 | +--- <tool>*
 | | |
 | | +--- [Extension Point]
 | |
 | +--- <prop-group>*
 | | |
 | | +--- <prop>*
 | |
 | +--- [Extension Point]
 | |
 | +--- <note>*
 |
 +--- <body>1
 |
 +--- <group>*
 | |
 | +--- <context-group>*
 | | |
 | | +--- <context>+
 | |
 | +--- <count-group>*
 | | |
 | | +--- <count>*
 | |
 | +--- <prop-group>*
 | | |
 | | +--- <prop>*
 | |
 | +--- [Extension Point]
 | |
 | +--- <note>*
 | |
 | +--- At least one of: (<group>* <trans-unit>* <bin-unit>*)
 |
 +--- <trans-unit>*
 | |
 | +--- <source>1
 | | |
 | | +--- [Inline Elements]
 | |
 | +--- <target>?
 | | |
 | | +--- [Inline Elements]
 | |
 | +--- <context-group>*
 | | |
 | | +--- <context>+
 | |
 | +--- <count-group>*
 | | |
 | | +--- <count>*
 | |
 | +--- <prop-group>*
 | | |
 | | +--- <prop>*
 | |
 | +--- <seg-source>?
 | | |
 | | +--- [Inline Elements]
 | |
 | +--- [Extension Point]
 | |
 | +--- <note>*
 | |
 | +--- <alt-trans>*
 | |
 | +--- <context-group>*
 | | |
 | | +--- <context>+
 | |
 | +--- <source>?
 | | |
 | | +--- [Inline Elements]
 | | | +--- <target>+
 | | |
 | | +--- [Inline Elements]
 | |
 | +--- <prop-group>*
 | | |
 | | +--- <prop>*
 | |
 | +--- <seg-source>?
 | | |
 | | +--- [Inline Elements]
 | |
 | +--- [Extension Point]
 | |
 | +---- <note>*
 |
 +--- <bin-unit>*
 |
 +--- <bin-source>1 & <bin-target>?
 | |
 | +--- (<internal-file> | <external-file>)1
 |
 +--- <context-group>*
 | |
 | +--- <context>+
 |
 +--- <count-group>*
 | |
 | +--- <count>*
 |
 +--- <prop-group>*
 | |
 | +--- <prop>*
 |
 +--- [Extension Point]
 |
 +--- <note>*
 |
 +--- <trans-unit>*

Struct_Extension_Elements

Inline Elements:

---+--- <ph>*
 | |
 | +--- <sub>*
 | |
 | +--- [Inline Elements]
 |
 +--- <it>*
 | |
 | +--- <sub>*
 | |
 | +--- [Inline Elements]
 |
 +--- <bpt>*
 | |
 | +--- <sub>*
 | |
 | +--- [Inline Elements]
 |
 +--- <ept>*
 | |
 | +--- <sub>*
 | |
 | +--- [Inline Elements]
 |
 +--- <g>*
 | |
 | +--- [Inline Elements]
 |
 +--- <x/>*
 | |
 | +--- [Inline Elements]
 |
 +--- <bx/>*
 | |
 | +--- [Inline Elements]
 |
 +--- <ex/>*
 | |
 | +--- [Inline Elements]
 |
 +--- <mrk>*
 |
 +--- [Inline Elements]
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • This doesn't answer OP's question directly, I think. It might be helpful if you showed the xsd-generated versions of the classes that OP is interested in -- that way, OP can see what they did wrong. You probably also need to provide info on how to find xsd.exe, or link to a suitable docs page. – canton7 Jan 19 '22 at 11:04