【问题标题】:Linq to XML: parse some elements and skip some elementsLinq to XML:解析一些元素并跳过一些元素
【发布时间】:2012-08-10 05:37:44
【问题描述】:

我正在尝试使用Linq to XML 解析来自XDocument 实例的数据并将其存储在IEnumerable<MyClass> 中。我不想从 xml 文档中获取每个元素,所以我使用 ElementAt(#index) 来获取值。但是有时我想要的元素不在文档中,然后我得到索引超出范围异常。有没有更好的方法来解析这个文档中的值?代码如下:

XML 文档如下所示:

<someotherelement>   /* I dont want the "someotherelement" part either */
   <subelement></subelement>
   <subelement></subelement>
</someotherelement>
<result>
   <doc>
      <int name="personid">8394</int> /* I don't want this value so I am skipping it */
      <str name="name">James</str>
      <str name="address">30 Awesome Lane</str>
      <arr name="randomearray"> /* I want to skip this too */
         <str name="random1">SomeValue</str>
         <str name="random2">SomeValue</str>
         <str name="random2">SomeValue</str>
      </arr>
      <str name="city">Awesome City</str>
      <str name="state">CA</str>
      <int name="zipcode">84392</int>
      <str name="country">USA</str>
      <str name="phonenumber">8309933820</str>
      <date name="reportdate">2012-07-27T06:01:05.256Z</date>
   </doc>

   /* This is missing address and country */
   <doc>
      <int name="personid">10394</int> /* I don't want this value so I am skipping it */
      <str name="name">Mathew</str>
      <arr name="randomearray"> /* I want to skip this too */
         <str name="random1">SomeValue</str>
         <str name="random2">SomeValue</str>
         <str name="random2">SomeValue</str>
      </arr>
      <str name="city">Not Awesome City</str>
      <str name="state">CA</str>
      <str name="zipcode">58439</str>
      <str name="phonenumber">8309933820</str>
      <date name="reportdate">2012-07-27T06:01:05.256Z</date>
   </doc>
</result>    

类:

public class Doc
{
    public string Name {get;set;}
    public string Address{get;set;}
    public string City {get;set;}
    public string State {get;set;}
    public int ZipCode {get;set;}
    public string Country {get;set;}        
    public string PhoneNumber {get;set;}
    public DateTime ReportDate {get;set;}
}

Linq 转 Xml

string pathToXml = "http://www.foo.com/something";
var doc = XDocument.Load(pathToXml);
IEnumerable<Doc> myDoc = from item in doc.Descendants("doc")
                 select new Doc
                 {
                   Name = item.Element("str").Value,
                   Address = item.Element("str").ElementsAfterSelf("str").First().Value,
                   City = item.Element("str").ElementsAfterSelf("str").ElementAt(1).Value,
                   State = item.Element("str").ElementsAfterSelf("str").ElementAt(2).Value,
                   ZipCode = Convert.ToInt32(item.Element("int").Value)
                   Country = item.Element("str").ElementsAfterSelf("str").ElementAt(3).Value,
                   PhoneNumber = item.Element("str").ElementsAfterSelf("str").ElementAt(4).Value,
                   ReportDate = Convert.ToDateTime(item.Element("date").Value)
                 };

【问题讨论】:

    标签: c# xml linq linq-to-xml


    【解决方案1】:

    您可能希望使用XPath,它允许您更舒适地指定元素,例如使用它们的属性值,这在您的情况下似乎很有用。

    结合扩展方法避免重复语句:

    public static string GetElementValue(this XElement element, string query)
    {
        var elem = element.XPathSelectElement(query);
        return elem == null ? null : elem.Value;
    }
    

    一个例子:

    select new Doc
    {
        Name = item.GetElementValue("str[@name='name']"),
        ...
    }
    

    【讨论】:

    • XPath 在这里很有意义。您可以使用我 providedGetValue() 扩展方法,然后此示例清理为:Name = item.XPathSelectElement("str[@name='name']").GetValue(), ...
    • 太棒了,谢谢。虽然你的答案和sblom 的答案都很好,但我喜欢你的答案,因为它简短而干净。再次感谢。
    【解决方案2】:

    我通过添加扩展方法解决了这个问题:

    public static class Extensions {
      public static string GetValue(this XElement element) {
        return element == null ? null : element.Value;
      }
    }
    

    然后使用基于Attribute() 的值选择:

    IEnumerable<Doc> myDoc = from item in doc.Descendants("doc")
                     select new Doc
                     {
                       Name = item.Element("str").Value,
                       Address = item.Element("str").ElementsAfterSelf("str").First().Value,
                       City = item.Element("str").ElementsAfterSelf("str").Where(el => (string)el.Attribute("name") == "city").FirstOrDefault().GetValue(),
                       State = item.Element("str").ElementsAfterSelf("str").Where(el => (string)el.Attribute("name") == "state").FirstOrDefault().GetValue(),
                       ZipCode = Convert.ToInt32(item.Element("int").Value),
                       Country = item.Element("str").ElementsAfterSelf("str").Where(el => (string)el.Attribute("name") == "country").FirstOrDefault().GetValue(),
                       PhoneNumber = item.Element("str").ElementsAfterSelf("str").Where(el => (string)el.Attribute("name") == "phonenumber").FirstOrDefault().GetValue(),
                       ReportDate = Convert.ToDateTime(item.Element("date").Value)
                     };
    

    该扩展方法可能有一个内置方法,但我不知道。

    【讨论】:

    • 感谢 sblom,您的回答也很有效,我将保留这两个答案作为未来的参考。我很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    相关资源
    最近更新 更多