[英]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.