反序列化动态XML

时间:2016-02-22 13:45:22

标签: c# xml xml-serialization

下面的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; } }

    }

1 个答案:

答案 0 :(得分:2)

由于您不知道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]而不是Hits标记Hits数组,则可以取消[XmlElement]课程,如下所示:

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

indexer。见Using Indexers (C# Programming Guide)。我添加了它,所以很容易做到这样的事情:

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

索引器查找具有指定名称的第一个XML元素,并返回其text value。如果你不想要它,你可以把它留下来 - 这只是为了方便。