简体   繁体   English

使用内部节点解析xml

[英]Parsing xml with inner nodes

I'm trying to parse the xml given below: 我正在尝试解析下面给出的xml:

<Item status="SUCCESS" message="">
   <ItemDate>12/21/2012
      <ItemType>MyType1
         <ItemUrl title="ItemTitle">http://www.itemurl1.com</ItemUrl>
      </ItemType>
   </ItemDate>
   <ItemDate>12/22/2012
      <ItemType>MyType2
         <ItemUrl title="Item2Title">http://www.itemurl2.com</ItemUrl>
      </ItemType>
   </ItemDate>
</Item>

As you could see I'm not sure whether we can call this xml, but this si what I get out of a legacy service. 如您所见,我不确定我们是否可以调用此xml,但这与我从旧版服务中得到的东西无关。 What I'm after is to parse this and load it into an object graph. 我需要的是解析它并将其加载到对象图中。 My object model is as below: 我的对象模型如下:

 public class Item
    {
        public string Date { get; set; }
        public string Type { get; set; }
        public string Url { get; set; }
        public string Title { get; set; }
    }

So, basically when I'm done with parsing the above xml/string I get a collection of Item objects. 因此,基本上,当我完成上述xml / string的解析后,便得到了Item对象的集合。 Can you please suggest me how to achieve this with some code snippet? 您能否建议我如何通过一些代码片段实现这一目标?

I tried with XDocument, but I was not able to do it given the peculiar structure of xml. 我尝试使用XDocument,但是鉴于xml的特殊结构,我无法做到这一点。

Thanks, -Mike 谢谢,-迈克

XDocument xdoc = XDocument.Load(path_to_xml);
var query = from date in xdoc.Descendants("ItemDate")
            let type = date.Element("ItemType")
            let url = type.Element("ItemUrl")
            select new Item()
            {
                ItemDate = ((XText)date.FirstNode).Value,
                ItemType = ((XText)type.FirstNode).Value,
                ItemUrl = (string)url,
                ItemTitle = (string)url.Attribute("title"),
            };

As an alternative to lazyberezovsky's Linq2Xml projection, you might also consider doing the flattening using an Xml Transform before loading the Xml. 作为lazyberezovsky's Linq2Xml投影的替代方法,您还可以考虑在加载Xml之前使用Xml Transform进行展平。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0"
                >
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes" />

    <xsl:template match="/">
        <Items>
            <xsl:apply-templates select="Item/ItemDate" />
        </Items>
    </xsl:template>

    <xsl:template match="ItemDate">
        <Item>
            <xsl:attribute name="ItemDate">
                <xsl:value-of select="normalize-space(./text()[1])" />
            </xsl:attribute>
            <xsl:attribute name="ItemType">
                <xsl:value-of select="normalize-space(ItemType/text()[1])" />
            </xsl:attribute>
            <xsl:attribute name="ItemUrl">
                <xsl:value-of select="normalize-space(ItemType/ItemUrl/text()[1])" />
            </xsl:attribute>
            <xsl:attribute name="ItemTitle">
                <xsl:value-of select="normalize-space(ItemType/ItemUrl/@title)" />
            </xsl:attribute>
        </Item>
    </xsl:template>
</xsl:stylesheet>

This produces the following Xml, which is straightforward to deserialize, eg using the [XmlAttribute] attribute with XmlDocument. 这将产生以下Xml,可直接对其进行反序列化,例如,将XmlDocument 属性[XmlAttribute] 属性一起使用。

<Items>
  <Item ItemDate="12/21/2012" ItemType="MyType1" ItemUrl="http://www.itemurl1.com" ItemTitle="ItemTitle" />
  <Item ItemDate="12/22/2012" ItemType="MyType2" ItemUrl="http://www.itemurl2.com" ItemTitle="Item2Title" />
</Items>

Because you have the node Item only once in the sent xml you get only one Item from lazyberezovsky's code. 因为在发送的xml中只有一次节点Item,所以从lazyberezovsky的代码中只能得到一个Item。 And that is correct. 那是正确的。 I suppose you want to get items but load them by ItemDate nodes. 我想您想获取项目,但要通过ItemDate节点加载它们。 To do so use the following modified code: 为此,请使用以下修改后的代码:

XDocument xdoc = XDocument.Load(new StringReader(xml));
var query = from i in xdoc.Descendants( "ItemDate" )
                    let date = i
                    let type = date.Element("ItemType")
                    let url = type.Element("ItemUrl")
                    select new Item()
                            {
                                Date = ((XText) date.FirstNode).Value,
                                Type = ((XText) type.FirstNode).Value,
                                Url = (string) url,
                                Title = (string) url.Attribute("title"),
                            };
        var items = query.ToList();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM