打印出嵌套的匿名类型

时间:2015-07-10 21:02:30

标签: c# xml linq

我有一个具有以下结构的xml文件;

 <Product ID="Sample A" UserTypeID="TYPE_PRD_RANGE">
      <MultiValues>
      <Value>
       <Value AttributeId = "Att_1">Value1</Value>
      </MultiValues>
      <Values AttributeId = "Att_2">
        <Value AttributeId = "Att_3">Value1</Value>
        <Value AttributeId = "Att_4">Value2</Value>
        <Value AttributeId = "Att_5">Value3</Value>
        <Value AttributeId = "Att_6">Value4</Value>
      </Values>
      <Product ID="Sample A_1" UserTypeID="SUB_RANGE">
        <Values AttributeId = "Att_2_5">
          <Value AttributeId = "Att_2_4">Value1</Value>
          <Value AttributeId = "Att_2_3">Value2</Value>
          <Value AttributeId = "Att_2_1">Value3</Value>
          <Value AttributeId = "Att_2_2">Value4</Value>
        </Values>
      </Product>
      <Product ID="Sample A_1_1" UserTypeID="ITEM">
        <Values AttributeId = "12345">
          <Value AttributeId = "Att_2_1_1">Value1</Value>
          <Value AttributeId = "Att_2_2_1">Value2</Value>
          <Value AttributeId = "Att_2_3_1">Value3</Value>
          <Value AttributeId = "Att_2_4_1">Value4</Value>
        </Values>
      </Product>    
   </Product>

我有一个类似于下面的LINQ查询,有两个嵌套的匿名类型

var rangeProducts = xml.Descendants("Product")
                     .Where(x => (string)x.Attribute("UserTypeID") == TYPE_PRD_RANGE);

var rangeproductDetails = rangeProducts.Select(x => new
        {

            ID = (String)x.Attribute("ID"),
            UserTypeID = (String)x.Attribute("UserTypeID"),
                                Values = x.Descendants("Value")
                                .Where(y => (string)y.Attribute("AttributeID") == "Att_1" ),

            //sub group for PRD_SUB_RANGE
            descendants = x.Descendants("Product")
                         .Where(y => (string)y.Attribute("UserTypeID")=="TYPE_PRD_SUBRANGE")
                         .Select(n => new
        {
            //group for items.
            children = n.Descendants("Product")
                          .Where(y => (string)y.Attribute("UserTypeID") == "ITEM")
                          .Select(m => new
            {

                ID = (String)m.Attribute("ID"),
                UserTypeID = (String)m.Attribute("UserTypeID"),
                Values = m.Descendants("Value")
                  .Where(y =>(string)y.Attribute("AttributeID")) == "Att_2_1_1"),
            },

            //for PRD_SUB_RANGE
            ID = (String)n.Attribute("ID"),
            UserTypeID = (String)n.Attribute("UserTypeID"),
            Values = n.Descendants("Value")
              .Where(y => ((string)y.Attribute("AttributeID")) == "Att_2_4"),

        })

我正在尝试以下列格式将查询结果写入控制台或文本文件

"range_Product ID" ,"range_Attribute 1.Value", 
    "subrange Product_ID", "subrange_Attribute2.Value" 
        Item Product_ID,  "item_Attribute_1.Value" ,"item_Attribute_2.Value"
        Item Product_ID,  "item_Attribute_1.Value" ,"item_Attribute_2.Value"

目前我可以做类似的事情:

"range_Product ID" ,"range_Attribute 1.Value", 
    "subrange Product_ID", "subrange_Attribute2.Value" 
    "subrange Product_ID", "subrange_Attribute2.Value" 
        Item Product_ID,  "item_Attribute_1.Value" ,"item_Attribute_2.Value"
        Item Product_ID,  "item_Attribute_1.Value" ,"item_Attribute_2.Value"

但我希望首先打印每个子范围下的每个项目。我在这里吠叫错误的树,或者这甚至可能远远不可能?我有建议简单地将XML反序列化为POCO,但是没有人能够说出我正在寻找的是否可能。

编辑:样本所需的输出。

"Sample A"  "Value1"
  "Sample A_1"  "Value3"
     Sample A_1_1  "Value 1" "Value 2" 
     Sample A_1_2    "Value1" "Value2" 

1 个答案:

答案 0 :(得分:0)

转换XML文本输出绝对是可行的。一些建议

首先,我没有看到在这里使用匿名类型的好处。有一个定义的顶级类来吸收IMO中的所有必要信息,可以更容易地推断出你正在使用的数据的形状。这并不意味着你需要序列化;您仍然可以从XML手动填充对象,这可能会减少工作量,并且可以让您更好地定义最终形状。

然后,您可以将方法与以您认为合适的方式将其数据输出到控制台的类相关联(即使只是覆盖ToString()

另请查看扩展方法XPathEvaluate。它将使您的XML查询更具可读性和简洁性。

编辑:既然你提供了你想要的样本,这里有一个解决方案

public void OutputProductElement( XElement inElem, int inIndentLevel )
{
    string theIndentation = new string( Enumerable.Repeat( '\t', inIndentLevel ).ToArray());

    var theValueElements = inElem.XPathSelectElements( "MultiValues/Value" ).Concat(
        inElem.XPathSelectElements( "Values/Value" )
        );

    string theValueList = string.Join( " ", theValueElements.Select( elem => @"""" + elem.Value + @"""" ) );

    Console.Out.WriteLine( theIndentation + @"""" + (string)inElem.Attribute("ID") + @""" " + theValueList  );

    //no print all children elemnts
    inElem.Elements( "Product" ).ToList().ForEach( elem => OutputProductElement( elem, inIndentLevel + 1 ) );
}

以下是输出:

"Sample A" "Value1" "Value1" "Value2" "Value3" "Value4"
  "Sample A_1" "Value1" "Value2" "Value3" "Value4"
  "Sample A_1_1" "Value1" "Value2" "Value3" "Value4"

希望我没有为你做功课:)