反序列化动态 XML [英] Deserialize dynamic XML

查看:31
本文介绍了反序列化动态 XML的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的XML总是采用这种格式,但是节点下的元素是动态的,每次的名称或项目数可能不同.是否可以动态获取节点下的元素

The XML below always comes in this format, but the elements under the <Hit> node are dynamic, the name or number of items could be different each time. Is it possible to get the elements under the <Hit> node dynamically.

<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,因为我已经定义了属性,但我需要让它们都是动态的.>

here's the C# code, it's working fine and get the id from the <Hit> node since I already defined the property, but I need to get all of them dynamic.

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

Edit 2://命中类代码

Edit 2: // Hit class code

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

    }

推荐答案

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

Since you don't know what elements might be present in your Hit class, you can add a List<XElement> property to you class and attach the [XmlAnyElement] attribute to it. It will then capture any and all unknown elements in the XML for the class. Once the elements are deserialized, you can add API properties to query for elements with specific names, for instance:

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],像这样:

Incidentally, you can eliminate your Hits class if you mark the Hits array with [XmlArray] rather than [XmlElement], like so:

[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# 编程指南).我添加了它,因此可以轻松执行以下操作:

Is an indexer. See Using Indexers (C# Programming Guide). I added it so it would be easy to do things like:

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

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

The indexer looks for the first XML element with the specified name, and returns its text value. If you don't want it, you can leave it out -- it's just for convenience.

这篇关于反序列化动态 XML的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆