解析xml和我的代码变得丑陋,更优雅的方式来做到这一点?

时间:2014-05-28 22:06:50

标签: c# xml linq

我有以下XML:

<propertyMetrics month="12" year="2003" propertyId="3923837">
<metric name="siteTotal" uom="kBtu" dataType="numeric">
    <value>241609.4</value>
</metric>
<metric name="waterUseTotal" dataType="numeric">
    <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</metric>
<metric name="propGrossFloorArea" uom="ft²" dataType="numeric">
    <value>20429</value>
</metric>
<metric name="totalGHGEmissions" uom="MtCO2e" dataType="numeric">
    <value>21.2</value>
</metric>
<metric name="greenPowerOnSite" dataType="numeric">
    <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</metric>
<metric name="energyBaselineDate" dataType="date">
    <value>2010-12-31</value>
</metric>
<metric name="score" dataType="numeric">
    <value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</metric>

我正在尝试关联&#34;名称&#34;属性为&#34;值&#34;元素和&#34; uom&#34;属性(如果存在)。

我原来是这样做的:

var propMetrics = doc.Descendants("metric")
.Where(e => !string.IsNullOrEmpty(e.Element("value").Value))
.ToDictionary(e => e.Attribute("name").Value, e => new { uom = e.Attribute("uom").Value, value =(double) e.Element("value") });

当没有&#34; uom&#34;属性。所以现在我做了两个LIQN调用,看起来更加丑陋的代码:

var propMetrics = doc.Descendants("metric")
                    .Where(e => !string.IsNullOrEmpty(e.Element("value").Value) && !(e.FirstAttribute.Value == "energyBaselineDate") && !(e.FirstAttribute.Value == "score"))
                    .ToDictionary(e => e.Attribute("name").Value,
                    e => new 
                        { 
                            uom = e.Attribute("uom").Value, 
                            value = (double)e.Element("value") 
                        });

        foreach(var x in propMetrics)
        {
            builder.Append(x.Key + ": " + x.Value.value + "<br>\n" + "uom: " + x.Value.uom + "<br>\n");
        }

        var score = doc.Descendants("metric")
                    .Where(e => !string.IsNullOrEmpty(e.Element("value").Value) && (e.FirstAttribute.Value == "energyBaselineDate") || (e.FirstAttribute.Value == "score"))
                    .Select(e => new {
                            name = e.Attribute("name").Value, 
                            value = (string)e.Element("value")});

        foreach(var x in score)
        {
            builder.Append(x.name + ": " + x.value + "<br>\n");
        }

有一种简单的方法吗?可能在单个LINQ查询中?

2 个答案:

答案 0 :(得分:2)

我想建议使用序列化模型进行复杂的xml读取和编辑会更容易。您可以轻松地将xml转换为c#对象,然后根据需要编辑对象属性。将xml转换为对象可以像这样轻松地完成:

static List<Metric> DeserializeFromXML(string xmlString)
{
   XmlSerializer deserializer = new XmlSerializer(typeof(List<Metric>));
   List<Metric> metrics; 
   metrics = (List<Metric>)deserializer.Deserialize(xmlString);

   return metrics;
}

同样,您可以使用以下内容将对象转换回xml:

static public string SerializeToXML(List<Metric> metrics)
{
    XmlSerializer serializer = new XmlSerializer(typeof(List<Metric>));
    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, metrics);

        return writer.ToString();
    }
}

根据您提供的xml,您将用于序列化进出的c#Metric对象看起来应该如下所示:

public class Metric
{
    public string name { get; set; }
    public string uom { get; set; }
    public string dataType { get; set; }
    public string value { get; set; }
}

答案 1 :(得分:0)

var propMetrics = (
    from e in doc.Descendants( "metric" )
    where !string.IsNullOrEmpty( e.Element( "value" ).Value )
    let auom = e.Attribute( "uom" )
    select new {
        key = e.Attribute( "name" ).Value,
        value = new {
            value = (double)e.Element( "value" ),
            uom = auom != null ? auom.Value : ""
        }
    } ).ToDictionary( p => p.key, p => p.value );