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.

6
  • 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 is available so you should be able to generate classes using xsd.exe or svcutil.exe, or an open source class generation tool Commented Jan 19, 2022 at 9:43
  • 1
    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 Commented Jan 19, 2022 at 9: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 Commented Jan 19, 2022 at 9:47
  • The Net library for arrays/list defaults to two layers of tags <parent><child></child><child></child><child></child></parent> 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. Commented Jan 19, 2022 at 10:01
  • 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 Commented Jan 19, 2022 at 10:58

3 Answers 3

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; } 
}
Sign up to request clarification or add additional context in comments.

Comments

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

4 Comments

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
@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.
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 I see a lot of missing info, even once you remove the SAP extensions.
@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!
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]

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.