簡體   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