使用具有多个属性值的xpath获取xml doc子节点

时间:2018-05-08 18:45:30

标签: c# xml

给定具有以下结构的xml

<Commodity name="coffee" title="Coffee" value="7">
  <Specs>
     ..elements removed
  </Specs>
  <ContractMonths lasttradedaterule="Eight business days prior to the last business day of the delivery month"
            firstnoticedaterule="Seven business days prior to first business day of delivery month">
     ..elements removed
  </ContractMonths>
 <Options tf="true">
   <OptionMonths delimeter="comma"
             expirationdaterule="Second Friday of the calendar month preceding such regular or serial
                option month; provided, however, that for each option, there will be a minimum of four
                trading days between the last trading day of the expiring option and the first notice
                day of the expiring future">
    <Year value="2015">
      ..elements removed
    </Year>
    <Year value="2016">
      ..elements removed
    </Year>
    <Year value="2017">
     ..elements removed
    </Year>
    <Year value="2018">
      <Jan expiration="" associatedcontract="Mar" />
      <Feb expiration="" associatedcontract="Mar" />
      <Mar expiration="02/12/18" associatedcontract="Mar" />
      <Apr expiration="" associatedcontract="May" />
      <May expiration="04/08/18" associatedcontract="May" />
      <Jun expiration="05/11/18" associatedcontract="Jul" />
      <Jul expiration="06/08/18" associatedcontract="Jul" />
      <Aug expiration="07/13/18" associatedcontract="Sep" />
      <Sep expiration="08/10/18" associatedcontract="Sep" />
      <Oct expiration="" associatedcontract="Dec" />
      <Nov expiration="" associatedcontract="Dec" />
      <Dec expiration="11/09/18" associatedcontract="Dec" />
    </Year>
  <Year value="2019">
   ..elements removed
  </Year>     
</OptionMonths>

有超过25种商品元素

我可以使用名称属性值

来检索我想要的商品元素
 var doc = XDocument.Load(@"https://batlgroupimages.blob.core.windows.net/accessibleimages/CommodityData.xml");

        IEnumerable<XElement> elem =
            doc.Descendants("Commodity").Where(el =>
            {
                var xAttribute = el.Attribute("name");
                return xAttribute != null && xAttribute.Value == commodity;
            });

我需要进一步向下钻取以获取年元素的节点列表,因为Year元素的value属性等于我传入的任何年份。

我试图在一个声明中做到这一点

var dates = elem.Descendants("Options/@tf='true'/OptionMonths/Year/@value='2015'");

它正确读取(对我来说)获取选项具有tf值为true的后代,获取OptionMonths / Years年份值= 2015

我可以用更短的步骤完成,但我确定有一个更快的解决方案。

更新 根据jdweng的回答,我想出了以下内容,它将返回传递给方法的年份

var year = elem.Descendants("Options")
            .Where(x => x.Attribute("tf")?.Value == "true").Descendants("Year")
            .Where(y => (string)y.Attribute("value") == yearvalue);

1 个答案:

答案 0 :(得分:1)

请尝试以下操作:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            string xAttribute = "coffee";
            Dictionary<int, Dictionary<string, KeyValuePair<string, string>>> dict = doc.Descendants("Commodity").Where(el => xAttribute == (string)el.Attribute("name"))
                .Select(x => x.Descendants("Year")
                .GroupBy(s => (int)s.Attribute("value"), t => t.Elements()
                    .GroupBy(u => u.Name.LocalName, v => new KeyValuePair<string, string>((string)v.Attribute("expiration"), (string)v.Attribute("associatedcontract")))
                        .ToDictionary(u => u.Key, v => v.FirstOrDefault()))
                        .ToDictionary(s => s.Key, t => t.FirstOrDefault())).FirstOrDefault();

        }
    }
}