繁体   English   中英

在C#中选择通过Linq通过两个子节点选择的节点

[英]select the nodes that pass the selection of two subnodes with Linq in C#

编辑根据@Gert Arnold的建议,我决定编辑并更彻底地格式化我的问题。

我一直在尝试通过Linq选择传递id和value条件的节点。 在我来说,我需要的series有两个特定节点value的中的属性SeriesKey节点。

这是我的XML字符串(仅供参考,如果发现任何标记错误,则可能是由于我的缩进错误所致,原始文件是XML有效的

<message:GenericData xmlns:footer="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message/footer" 
                     xmlns:generic="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic" 
                     xmlns:message="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message" 
                     xmlns:common="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/common" 
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<message:DataSet>
  <generic:Series>
      <generic:SeriesKey>
           <generic:Value id="GEO" value="124"/>
           <generic:Value id="PRODUCT" value="4400"/>
           <generic:Value id="FIN" value="03"/>
           <generic:Value id="ENERGY_UNITS" value="WSR"/>
      </generic:SeriesKey>
      <generic:Obs>
          <generic:ObsDimension id="TIME_PERIOD" value="1999"/>
          <generic:ObsValue value="0"/>
          <generic:Attributes>
              <generic:Value id="UNIT_SUFFIX" value="R"/>
          </generic:Attributes>
      </generic:Obs>
      <generic:Obs>
          <generic:ObsDimension id="TIME_PERIOD" value="2000"/>
          <generic:ObsValue value="0"/>
      <generic:Attributes>
      <generic:Value id="UNIT_SUFFIX" value="R"/>
      </generic:Attributes>
      </generic:Obs>
 </generic:Series>
 <generic:Series>
     <generic:SeriesKey>
         <generic:Value id="GEO" value="124"/>
         <generic:Value id="PRODUCT" value="4100"/>
         <generic:Value id="FIN" value="03"/>
         <generic:Value id="ENERGY_UNITS" value="WSR"/>
     </generic:SeriesKey>
     <generic:Obs>
         <generic:ObsDimension id="TIME_PERIOD" value="1999"/>
         <generic:ObsValue value="8246"/>
         <generic:Attributes>
             <generic:Value id="UNIT_SUFFIX" value="R"/>
         </generic:Attributes>
     </generic:Obs>
     <generic:Obs>
         <generic:ObsDimension id="TIME_PERIOD" value="2000"/>
         <generic:ObsValue value="40733"/>
         <generic:Attributes>
             <generic:Value id="UNIT_SUFFIX" value="R"/>
         </generic:Attributes>
     </generic:Obs>
   </generic:Series>
   <generic:Series>
       <generic:SeriesKey>
           <generic:Value id="GEO" value="124"/>
           <generic:Value id="PRODUCT" value="4200"/>
           <generic:Value id="FIN" value="03"/>
           <generic:Value id="ENERGY_UNITS" value="WSR"/>
       </generic:SeriesKey>
       <generic:Obs>
           <generic:ObsDimension id="TIME_PERIOD" value="1999"/>
           <generic:ObsValue value="279"/>
           <generic:Attributes>
               <generic:Value id="UNIT_SUFFIX" value="R"/>
           </generic:Attributes>
       </generic:Obs>
       <generic:Obs>
           <generic:ObsDimension id="TIME_PERIOD" value="2000"/>
           <generic:ObsValue value="324"/>
           <generic:Attributes>
               <generic:Value id="UNIT_SUFFIX" value="R"/>
           </generic:Attributes>
       </generic:Obs>
    </generic:Series>
</message:DataSet>
</message:GenericData>

我尝试使用查询方式,只是使用where语句中的逻辑运算符创建了一系列步骤。 我已经附上了有问题的方法。 此时它接受XML字符串(一个以上)和两个过滤标准,即EnergyProduct过滤PRODUCT属性和EconSector过滤FIN属性。

    public IEnumerable<XElement> DataSetFilter(string XmlString, string EnergyProduct, string EconSector)
    {
        XDocument sdmx_response = XDocument.Parse(XmlString);
        XNamespace message = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message";
        XNamespace generic = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic";
        IEnumerable<XElement> DataSet = sdmx_response.Root.Elements(message + "DataSet");
        IEnumerable<XElement> Series = from series in DataSet.Elements(generic + "Series")
                     from serieskey in series.Elements(generic + "SeriesKey")
                     from value in serieskey.Elements(generic + "Value")
                     where 
                     (
                         (string)value.Attribute("id") == "PRODUCT" && (string)value.Attribute("value") == EnergyProduct
                     ) || 
                     (
                         (string)value.Attribute("id") == "FIN" && (string)value.Attribute("value") == EconSector
                     )
                     select serieskey;
        IEnumerable <XElement> observationsSet = from observations in Series.Elements(generic + "Obs").Elements(generic + "ObsValue") select observations;
        return observationsSet;
    }

问题在于它会同时获取这两个属性的所有数据,例如与PRODUCT代码“ 4400”和FIN代码“ 03”匹配的数据,而我正在寻找的只是那些包含具有这些确切值的子节点的节点,两者都在同一SeriesKey 我当时正在考虑创建一个匿名对象,该对象包含要查询的xml元素,但出现错误,但我仍然困惑如何正确实现该对象。 谢谢你的帮助!

尝试以下:

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 sdmx_response = XDocument.Load(FILENAME);
            XNamespace message = sdmx_response.Root.GetDefaultNamespace();
            XNamespace generic = sdmx_response.Root.GetDefaultNamespace();

            IEnumerable<XElement> DataSet = sdmx_response.Root.Elements(message + "DataSet");
            IEnumerable<XElement> Series = DataSet.Elements(generic + "Series").Select(series => new XElement("Series", new object[] {
                new XElement("SeriesKey", 
                    series.Elements(generic + "SeriesKey").Elements("Value").Where(value =>((string)value.Attribute("id") == "PRODUCT" && (string)value.Attribute("value") == "Lumber") || ((string)value.Attribute("id") == "FIN" && (string)value.Attribute("export") == "Lumber"))
                    ),
                series.Elements(generic + "Obs")
            })).ToList();

        }
    }



}

我赞成并选择jdweng的答案作为最合适的解决方案。 这是我的代码。

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            IEnumerable<XElement> NormalizedDataSet = NormalizeGeneric(FILENAME);
            foreach (XElement Series in NormalizedDataSet)
            {
                Console.WriteLine(Series);
            }
        }

        public IEnumerable<XElement> NormalizeGeneric(string XmlString)
        {
            XDocument xml_response = XDocument.Parse(XmlString);
            XNamespace message = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message";
            XNamespace generic = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic";
            XElement SeriesSet = xml_response.Root;
            IEnumerable<XElement> SeriesObject = seriesSet.Elements(message + "DataSet")
                                                          .Elements(generic + "Series")
                                                          .Select(series => new XElement("Series", new object[]
            {
                new XElement("Metadata", 
                            series.Elements(generic + "SeriesKey")
                                  .Elements(generic + "Value")
                                  .Select(value => new XElement((string)value.Attribute("id"), new XAttribute("value", (string)value.Attribute("value"))))),
                new XElement("Data", 
                            series.Elements(generic + "Obs")
                                  .Select(observations => new XElement("Observation", new XAttribute((string)observations.Element(generic + "ObsDimension")
                                                                                                                         .Attribute("id"), (string)observations.Element(generic + "ObsDimension").Attribute("value")), new XAttribute("value", (string)observations.Element(generic + "ObsValue").Attribute("value")), new XElement("Attributes", observations.Elements(generic + "Attributes").Elements(generic + "Value").Select(attributes => new XElement((string)attributes.Attribute("id"), new XAttribute("value", (string)attributes.Attribute("value"))))))))
            })).ToArray();
            return SeriesObject;
        }
    }
}

我的代码和jdweng的代码之间的区别是,我还添加了包含实际数字的文件的Data部分。 数据集的“标准化”是不可避免的,因此更容易操纵值和过滤必要的节点。 谢谢您的迟钝回应和表示歉意。

暂无
暂无

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

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