反序列化动态 XML

本文关键字:XML 动态 反序列化 | 更新日期: 2023-09-27 18:35:44

下面的XML总是以这种格式出现,但<Hit>节点下的元素是动态的,每次的名称或项目数可能不同。是否可以动态获取<Hit>节点下的元素。

<SearchResponse>
    <Response>
        <Qtime>3</Qtime>
        <HitsPerPage>10</HitsPerPage>
    </Response>
    <HitsCount>
        <total>33</total>
        <start>0</start>
        <end>10</end>
    </HitsCount>
    <Hits>
        <Hit>
            <id type=''>123</id>
            <eid type=''>456</eid>
            <Title type='t'>
                <![CDATA[title goes here]]>
            </Title>
        </Hit>
        <Hit>
            <id type=''>123</id>
            <oid type=''>456</oid>
            <Title type='t'>
                <![CDATA[title goes here]]>
            </Title>
            <Description type='s'>
                <![CDATA[Description goes here]]>
            </Description>
        </Hit>
    </Hits>
</SearchResponse>

编辑:这是 C# 代码,它工作正常并从 <Hit> 节点获取 id,因为我已经定义了属性,但我需要让所有这些代码都动态起来。

[XmlRoot("SearchResponse")]
    public sealed class SearchResponse {
        [XmlElement("Response", Type = typeof(Response))]
        public Response[] Responses { get; set; }
        [XmlElement("HitsCount", Type = typeof(HitsCount))]
        public HitsCount[] HitsCount { get; set; }
        [XmlElement("Hits", Type = typeof(Hits))]
        public Hits[] Hits { get; set; }

        public static SearchResponse GetSearchResponseObject(string xmlString) {
            try {
                var reader = new StringReader(xmlString);
                var serializer = new XmlSerializer(typeof(SearchResponse));
                var instance = (SearchResponse)serializer.Deserialize(reader);
                return instance;
            } catch (Exception ex) {
                var asd = ex.Message;
                return null;
            }
        }
    }
    [Serializable]
    public class Response {
        [XmlElement("Qtime")]
        public string Qtime { get; set; }
        [XmlElement("HitsPerPage")]
        public string HitsPerPage { get; set; }
    }
    [Serializable]
    public class HitsCount {
        [XmlElement("total")]
        public string Total { get; set; }
        [XmlElement("start")]
        public string Start { get; set; }
        [XmlElement("end")]
        public string End { get; set; }
    }
    [Serializable]
    public class Hits {
        [XmlElement("Hit")]
        public Hit[] Hit { get; set; }
    }
    [Serializable]
    public class Hit {
        [XmlElement("id")]
        public string Id { get; set; }
    }

编辑 2://点击类代码

public class Hit {
        // Since "id" is expected in the XML, deserialize it explicitly.
        [XmlElement("id")]
        public string Id { get; set; }
        private readonly List<XElement> _elements = new List<XElement>();
        [XmlAnyElement]
        public List<XElement> Elements { get { return _elements; } }
    }

反序列化动态 XML

由于您不知道Hit类中可能存在哪些元素,因此可以将 List<XElement> 属性添加到类中,并将 [XmlAnyElement] 属性附加到该类。 然后,它将捕获类的 XML 中的任何和所有未知元素。 反序列化元素后,可以添加 API 属性来查询具有特定名称的元素,例如:

public class Hit
{
    // Since "id" is expected in the XML, deserialize it explicitly.
    [XmlElement("id")]
    public string Id { get; set; }
    private readonly List<XElement> elements = new List<XElement>();
    [XmlAnyElement]
    public List<XElement> Elements { get { return elements; } }
#region convenience methods
    public string this[XName name]
    {
        get
        {
            return Elements.Where(e => e.Name == name).Select(e => e.Value).FirstOrDefault();
        }
        set
        {
            var element = Elements.Where(e => e.Name == name).FirstOrDefault();
            if (element == null)
                Elements.Add(element = new XElement(name));
            element.Value = value;
        }
    }
    const string title = "Title";
    [XmlIgnore]
    public string Title
    {
        get
        {
            return this[title];
        }
        set
        {
            this[title] = value;
        }
    }
#endregion
}

顺便说一下,如果你用 [XmlArray] 而不是 [XmlElement] 标记Hits数组,你可以消除你的 Hits 类,如下所示:

[XmlRoot("SearchResponse")]
public sealed class SearchResponse
{
    [XmlElement("Response", Type = typeof(Response))]
    public Response[] Responses { get; set; }
    [XmlElement("HitsCount", Type = typeof(HitsCount))]
    public HitsCount[] HitsCount { get; set; }
    [XmlArray("Hits")] // Indicates that the hits will be serialized with an outer container element named "Hits".
    [XmlArrayItem("Hit")] // Indicates that each inner entry element will be named "Hit".
    public Hit [] Hits { get; set; }
}

更新

    public string this[XName name] { get; set; }

是一个索引器。 请参阅使用索引器(C# 编程指南)。 我添加了它,以便很容易执行以下操作:

var description = hit["Description"];
var title = hit["Title"];

索引器查找具有指定名称的第一个 XML 元素,并返回其文本值。 如果你不想要它,你可以把它排除在外——这只是为了方便。