2017-02-04 4 views
0

EDIT @Gert Arnoldの助言によれば、私は編集してより完全に私の質問を書式化しました。LinqをC言語で使用して2つのサブノードの選択肢を渡すノードを選択してください

私は、idと値の条件を渡すノードをLinq経由で選択しようとしています。私の場合、SeriesKeyノード内に2つの特定のvalue属性を持つノードを持つseriesが必要です。

ここで私はちょうどクエリの道を行くとしようとした私のXML文字列(あなたはどのマークアップのミスを見つけたならFYI、彼らは原因私のインデントのミスに、元のファイルは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文字列(上記の1つ)と2つのフィルタリング条件、つまり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要素を構成する匿名オブジェクトを作成することを考えていましたが、エラーが発生しましたが、それを適切に実装する方法はまだ混乱しています。 ありがとうございました!

+1

あなたのXMLは無効です。あなたがそれをhttp://www.xmlvalidation.comにアップロードすると、エラーが表示されます。 '16:要素タイプ「シリーズ」は、一致する終了タグ「」で終わらなければなりません。 ? – dbc

+0

ありがとうございます。コードを貼り付ける間に間違いをしたようです。私の場合、XML検証は問題ではありませんでした。 – Cristiansen

+0

'where|'節でなぜ' || 'を使うのか、なぜなら*両方の*条件を満たすサブノードが必要なのかどうか不明です。 – Tomer

答えて

2

は、次の試してみてください。

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(); 

     } 
    } 



} 
+3

このコード部分はOPの質問に答えるかもしれませんが、説明を追加すると答えがより役に立ちます。コードのみの回答には品質レビューのフラグが立てられている可能性があります。 –

0

私が最も適切なソリューションとしてjdwengの答えをupvotedして選択しました。これは私のコードです。

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の違いは、実際の数値を含むファイルのデータ部分も追加したことです。データセットの「正規化」は避けられないので、値を操作して必要なノードをフィルタする方が簡単です。遅れていることや押されたことに対する感謝と謝罪。

関連する問題