У меня проблема с созданием соответствующего класса для десериализации файла xml. Структура xml выглядит следующим образом:

<?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>

Как видите, у нас есть вложенные массивы внутри массивов. Кроме того, один из массивов имеет имя, которое нельзя назвать таким же именем для класса. Предварительно созданные классы:

[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; }
    } 

К сожалению, у меня есть проблема с завершением классов, чтобы получить исходные и целевые значения.

0
aszejda 19 Янв 2022 в 12:37
I have a problem to complete classes to get to and values. какая проблема? Помимо попыток использовать устаревший формат 1.2 вместо текущего 2.x. Как вы создавали классы? Я вижу, что XSD для XLIFF 1.2 доступен, поэтому вы должны иметь возможность создавать классы, используя xsd.exe или svcutil.exe, или инструмент генерации классов с открытым исходным кодом
 – 
Panagiotis Kanavos
19 Янв 2022 в 12:43
вы не должны наследовать от List<T>. Вместо этого предпочли композицию наследованию, что означает, что ваш body-класс имеет набор групп, в отличие от вашего body-класса являющегося таким коллекция
 – 
HimBromBeere
19 Янв 2022 в 12:43
1
При создании типов XmlSerializer для десериализации часто проще всего попробовать сериализовать свои классы, чтобы увидеть, что будет на выходе, и продолжать их настраивать, пока структура выходного XML не будет соответствовать ожидаемой. Тогда вы знаете, что они правильно десериализуют ваш ввод
 – 
canton7
19 Янв 2022 в 12:47
Сетевая библиотека для массивов/списков по умолчанию использует два слоя тегов , где родитель определяется с помощью [XmlArray( "parent")], а дочерний элемент определяется с помощью [XmlArrayItem("child")]. Если в Xml есть только один тег, вы должны добавить [XmlElement{"child")], чтобы изменить значение по умолчанию только на один тег.
 – 
jdweng
19 Янв 2022 в 13:01
1
Почему это адресовано мне? Очевидно, что если вы хотите проанализировать только подмножество XLIFF (как хочет сделать OP - они даже игнорируют атрибуты), вполне возможно написать небольшое количество классов вручную. В противном случае xsd.exe и XmlSchemaClassGenerator, конечно, ваши друзья
 – 
canton7
19 Янв 2022 в 13:58

3 ответа

Лучший ответ

XLIFF намного сложнее и имеет гораздо больше элементов, чем этот. Текущая версия — 2.1, но более старая версия 1.2 также описана в сайт OASIS вместе с ссылки на схему XSD

Почти все стандартизированные документы XML основаны на схеме XML, доступной в виде документа XSD (определение схемы XML).

Вы можете использовать инструмент xsd.exe для создания классов C# из файла XSD. Вы можете загрузить, например, http://docs.oasis-open.org/xliff/v1.2/cs02/xliff-core-1.2-strict.xsd локально как xliff.xsd, а затем выполнить

xsd xliff.xsd /c 

Чтобы сгенерировать файл xliff.cs со всеми классами.

В результате получается более 1000 строк, поэтому его нельзя просто вставить сюда.

древовидная структура, скопированная из документы, содержит много элементов:


<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
Panagiotis Kanavos 19 Янв 2022 в 13:00
Я думаю, это не отвечает на вопрос ОП напрямую. Было бы полезно, если бы вы показали сгенерированные xsd версии классов, которые интересуют OP, - таким образом, OP может увидеть, что они сделали неправильно. Возможно, вам также потребуется предоставить информацию о том, как найти xsd.exe, или ссылку на подходящую страницу документации.
 – 
canton7
19 Янв 2022 в 14:04

Вы можете использовать онлайн-инструмент для преобразования XML в модель C#: https://json2csharp.com/xml-to -csharp

Попробуйте использовать эту модель (созданную вышеуказанным инструментом):

// 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; } 
}
2
SeeSharp 19 Янв 2022 в 12:53

вы не должны наследовать от List<T>. Вместо этого вы выбрали композицию вместо наследования, что означает, что ваш body-класс имеет набор групп, в отличие от вашего body-класса, являющегося таким набором.

Таким образом, вы можете использовать эту структуру вместо этого:

[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; }
} 

Кроме того, вы должны рассмотреть возможность использования PascalCase для своих классов. Чтобы дать этим классам разные имена в сериализованном xml, вы можете использовать xml-атрибуты, например:

[XmlRott("body")]
public class Body
2
HimBromBeere 19 Янв 2022 в 12:55
XLIFF определяется схемой, которая намного сложнее, чем 5-6 элементов. Файл, сгенерированный xsd.exe, содержит более 1000 строк.
 – 
Panagiotis Kanavos
19 Янв 2022 в 12:58
1
Правда, но это не имеет отношения к реальной проблеме, ИМХО. Все остальные элементы не являются частью приведенного выше xml, поэтому для него будет достаточно этой простой структуры классов. То, что xsd также определяет больше классов, не означает, что они нам нужны.
 – 
HimBromBeere
19 Янв 2022 в 13:01
Сомневаюсь, что это настоящий документ. XLIFF используется для хранения данных локализации, поэтому любой практический документ будет содержать больше, чем этот образец. Нецелесообразно создавать классы вручную. Просматривая выборку XLIFF из SAP, я вижу много недостающей информации, даже если вы удалите расширения SAP.
 – 
Panagiotis Kanavos
19 Янв 2022 в 13:10
1
Прелесть XmlSerializer в том, что вы можете просто определить классы для интересующих вас фрагментов схемы, а все остальное будет игнорироваться десериализатором. Если вас интересует только часть файла, вам не нужно десериализовать его целиком!
 – 
canton7
19 Янв 2022 в 14:05