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