C# 反序列化问题 xml 数组中的数组和其他名称

C# Problem with deserialization xml with arrays in arrays and other names

我在创建适当的 class 以反序列化 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>

如您所见,我们在数组中嵌套了数组。此外,其中一个数组的名称不能与 class 的名称相同。预先创建 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; }
    } 

不幸的是,我无法完成 classes 以获取源值和目标值。

you should not inherit from List<T>. Instead chose composition over inheritance,这意味着您的 body-class 组集合,与您的 body 形成对比-class就是这样的合集。

所以你可以改用这个结构:

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

此外,您应该考虑为您的 classes 使用 PascalCase。要在序列化的 xml 中给这些 classes 不同的名称,您可以使用 xml 属性,例如:

[XmlRott("body")]
public class Body

您可以使用在线工具将 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; } 
}

XLIFF 比这复杂得多,元素也多得多。当前版本是 2.1,但更旧的 1.2 也在 the OASIS site, along with links to the XSD schema

中描述

几乎所有标准化的 XML 文档都基于 XML 模式,可作为 XSD 文档(XML 模式定义)获得。

您可以使用 xsd.exe 工具从 XSD 文件生成 C# 类。你可以下载例如 http://docs.oasis-open.org/xliff/v1.2/cs02/xliff-core-1.2-strict.xsd 本地为 xliff.xsd 然后执行

xsd xliff.xsd /c 

生成包含所有 类 的文件 xliff.cs

结果超过1000行,不能直接贴在这里

从文档复制的 tree structurelot 个元素:


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

这是使用 Cinchoo ETL 从 xml 中提取部分数据的另一种方法 - 一个开源库,无需创建分层 classes(使用 xsd.exe)

方法一:用POCOclass

定义 POCO class

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

使用 ChoXmlReader 解析和加载 xml,如下所示

using (var r = new ChoXmlReader<trans>("*** XML FILE PATH ***")
       .WithXPath("//trans-unit")
       .WithXmlNamespace("x", "urn:oasis:names:tc:xliff:document:1.2"))
{
    foreach (var rec in r)
        rec.Print();
}

示例 fiddle: https://dotnetfiddle.net/rsKZiQ

方法二:使用动态

使用 ChoXmlReader 解析和加载 xml,如下所示

using (var r = new ChoXmlReader("*** XML FILE PATH ***")
       .WithXPath("//trans-unit")
       .WithXmlNamespace("x", "urn:oasis:names:tc:xliff:document:1.2"))
{
    foreach (var rec in r)
        rec.Print();
}

示例 fiddle: https://dotnetfiddle.net/Xg3x7K

免责声明:我是该库的作者。