【问题标题】:Multiple selects within query查询中的多个选择
【发布时间】:2018-05-16 22:56:17
【问题描述】:

此查询正在从 xml 文件构建商品符号。

文件结构是

<Commodities>
  <Grains>
    <Commodity title="Corn" value="0" name="corn">
      <Specs>
        //other elements
        <SymbolRoot>
          <Platform value="ZC" name="globex"/>
          <Platform value="C " name="bloomberg"/>
        </SymbolRoot>
      </Specs>
      <ContractMonths firstnoticedaterule="" lasttradedaterule="The business day prior to the 15th calendar day of the contract month">
        <Month value="Mar">
         <Year value="2018" firstnoticedate="02/28/18" lasttradedate="03/14/18" dateformat="mm/dd/yy"/>
          <Year value="2019" firstnoticedate="02/28/19" lasttradedate="03/14/19" dateformat="mm/dd/yy"/>
          <Year value="2020" firstnoticedate="02/28/20" lasttradedate="03/13/20" dateformat="mm/dd/yy"/>
        </Month>
      </ContractMonths>
    </Commodity>
  </Grains>
<Commodities>

目前,我可以根据需要获取合约月份,但我还需要传入平台的符号根。现在它被硬编码为“C”

private List<string> GetAllSymbolsForContractMonths(CommodityList commodity, string platform)
{
    var symCode = string.Empty;
    var yrLastDigit = DateTime.Now.Year % 10;
    //get the contract month symbol codes
    var query = _doc.Descendants("Commodity")
            .Where(c => c.Attribute("name")?.Value == commodity.ToString().ToLower())
            .Descendants("ContractMonths").Elements("Month")
            .Select(v => "C " + SymbolHelpers.GetSymbolContractMonthLetter(v.Attribute("value")?.Value) + yrLastDigit + " Comdty")
            .ToList();

    return query;
}

我知道有一些方法可以对 Platform 元素的 value 属性进行选择并将该值设置为 symCode 变量,但我似乎无法正确处理。然后我可以用变量替换硬编码。

【问题讨论】:

    标签: c# xml linq-to-xml


    【解决方案1】:

    将您的查询一分为二。 首先,找到商品元素。

    从该元素中,找到平台符号。 然后,构建列表。

    private List<string> GetTypeFromVariable(CommodityList commodity, string platform)
    {
        var yrLastDigit = DateTime.Now.Year % 10;
    
        var commodityElement = _doc.Descendants("Commodity")
            .Where(x => x.Attribute("name")?.Value.Equals(commodity.ToString(), StringComparison.InvariantCultureIgnoreCase) ?? false)
            .Single();
    
        var symbol = commodityElement.Descendants("Platform")
            .Where(x => x.Attribute("name")?.Value.Equals(platform, StringComparison.InvariantCultureIgnoreCase) ?? false)
            .Single()
            .Attribute("value").Value;
    
        return commodityElement
            .Descendants("ContractMonths").Elements("Month")
                .Select(v => symbol + " " + SymbolHelpers.GetSymbolContractMonthLetter(v.Attribute("value")?.Value) + yrLastDigit + " Comdty")
                .ToList();
    }
    

    【讨论】:

    • 顺便说一下——为了使这段代码可测试,年份应该是一个参数,而不是基于计算机的时钟。
    • @gnud...我想的也差不多。试图一口气做到这一点。没有办法解决吗?让您了解可测试性参数。
    • 没有理由一口气完成。查询的第一部分,您可以在其中找到商品元素,无论如何都必须运行。不会有任何性能差异。而且拆分起来也清晰很多。
    • @gnud...ty 我从那个答案中学到了一些新的查询技巧。
    【解决方案2】:

    只是为了好玩,有一些很酷的网站可以将您的 XML 转换为 C# 类(例如Xml2CSharp.com)。使用该工具,您可以创建一组要反序列化的类,然后利用 LINQ to Objects。

    Commodities commodities = null;
    using (var stream = new StringReader(xmlString))
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Commodities));
        commodities = (Commodities) serializer.Deserialize(stream);
    }
    
    var commodityName = "corn";
    var platformName = "bloomberg";
    var year = "2018";
    var commodity = commodities.Grains.Commodity.Single(c => c.Name.Equals(commodityName, StringComparison.InvariantCultureIgnoreCase));
    var symbol = commodity.Specs.SymbolRoot.Platform.Single(p => p.Name.Equals(platformName, StringComparison.InvariantCultureIgnoreCase));
    var months = commodity.ContractMonths.Month.Year.Where(y => y.Value.Equals(year, StringComparison.InvariantCultureIgnoreCase));
    

    这是我使用该工具生成的类。这显然是更多的代码,但我喜欢使用具体的类。希望对您有所帮助。

    [XmlRoot(ElementName = "Platform")]
    public class Platform
    {
        [XmlAttribute(AttributeName = "value")]
        public string Value { get; set; }
        [XmlAttribute(AttributeName = "name")]
        public string Name { get; set; }
    }
    
    [XmlRoot(ElementName = "SymbolRoot")]
    public class SymbolRoot
    {
        [XmlElement(ElementName = "Platform")]
        public List<Platform> Platform { get; set; }
    }
    
    [XmlRoot(ElementName = "Specs")]
    public class Specs
    {
        [XmlElement(ElementName = "SymbolRoot")]
        public SymbolRoot SymbolRoot { get; set; }
    }
    
    [XmlRoot(ElementName = "Year")]
    public class Year
    {
        [XmlAttribute(AttributeName = "value")]
        public string Value { get; set; }
        [XmlAttribute(AttributeName = "firstnoticedate")]
        public string Firstnoticedate { get; set; }
        [XmlAttribute(AttributeName = "lasttradedate")]
        public string Lasttradedate { get; set; }
        [XmlAttribute(AttributeName = "dateformat")]
        public string Dateformat { get; set; }
    }
    
    [XmlRoot(ElementName = "Month")]
    public class Month
    {
        [XmlElement(ElementName = "Year")]
        public List<Year> Year { get; set; }
        [XmlAttribute(AttributeName = "value")]
        public string Value { get; set; }
    }
    
    [XmlRoot(ElementName = "ContractMonths")]
    public class ContractMonths
    {
        [XmlElement(ElementName = "Month")]
        public Month Month { get; set; }
        [XmlAttribute(AttributeName = "firstnoticedaterule")]
        public string Firstnoticedaterule { get; set; }
        [XmlAttribute(AttributeName = "lasttradedaterule")]
        public string Lasttradedaterule { get; set; }
    }
    
    [XmlRoot(ElementName = "Commodity")]
    public class Commodity
    {
        [XmlElement(ElementName = "Specs")]
        public Specs Specs { get; set; }
        [XmlElement(ElementName = "ContractMonths")]
        public ContractMonths ContractMonths { get; set; }
        [XmlAttribute(AttributeName = "title")]
        public string Title { get; set; }
        [XmlAttribute(AttributeName = "value")]
        public string Value { get; set; }
        [XmlAttribute(AttributeName = "name")]
        public string Name { get; set; }
    }
    
    [XmlRoot(ElementName = "Grains")]
    public class Grains
    {
        [XmlElement(ElementName = "Commodity")]
        public List<Commodity> Commodity { get; set; }
    }
    
    [XmlRoot(ElementName = "Commodities")]
    public class Commodities
    {
        [XmlElement(ElementName = "Grains")]
        public Grains Grains { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-29
      • 1970-01-01
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-30
      • 2021-05-28
      相关资源
      最近更新 更多