使用linq折叠要列出的子节点

时间:2012-07-17 07:26:06

标签: c# xml linq

我有一个定义xml的类和另一个定义候选的类,另一个类是候选类的列表。

我正在尝试根据xml中的节点数动态创建列表。

我尝试了所有类型的变化并没有任何效果,直到节点Candidates我获得了所有信息,但CandidateList始终为null。

public class Candidate
{
}

public class CandidateList : List<Candidate>
{
}

public class Request
{
    public CandidateList CandidateList { get; set; }
}
<?xml version="1.0" encoding="utf-8"?>
<Requests>
  <Request>
    <MidaClientID>1040</MidaClientID>
    <!--elided other elements-->
    <OrderDescription></OrderDescription>
    <Candidates>
      <Candidate>
        <QuestNum>6</QuestNum>
        <!--elided other elements-->
        <EventNum>012</EventNum>
      </Candidate>
      <Candidate>
        <QuestNum>6</QuestNum>
         <!--elided other elements-->
        <EventNum>012</EventNum>
      </Candidate>
    </Candidates>
  </Request>
</Requests>
try
{
    IEnumerable<Request> req = from r in input.Descendants("Request")
    select new Request()
    {
        MidaClientID = (int)r.Element("MidaClientID") != 0 ? (int)r.Element("MidaClientID") : 0,
        Password = (string)r.Element("MidaClientPassword") != null ? (string)r.Element("MidaClientPassword") : string.Empty,
        ClientNum = (int)r.Element("ClientNum") != 0 ? (int)r.Element("ClientNum") : 0,
        ClientName = (string)r.Element("ClientName") != null ? (string)r.Element("ClientName") : string.Empty,
        ContactNum = (int)r.Element("ContactNum") != 0 ? (int)r.Element("ContactNum") : 0,
        ContactFirstName = (string)r.Element("ContactFirstName") != null ? (string)r.Element("ContactFirstName") : string.Empty,
        ContactLastName = (string)r.Element("ContactLastName") != null ? (string)r.Element("ContactLastName") : string.Empty,
        ContactEmail = (string)r.Element("ContactEmail") != null ? (string)r.Element("ContactEmail") : "",
        OrderID = (int)r.Element("OrderID") != 0 ? (int)r.Element("OrderID") : 0,
        OrderDesc = (string)r.Element("OrderDescription") != null ? (string)r.Element("OrderDescription") : "",
        CandidateList = (from i in input.Root.Element("Candidates").Elements("Candidate")
            select new Candidate()
            {
                QuestNum = (int)r.Element("QuestNum") != 0 ? (int)r.Element("QuestNum") : 0,
                CandNum = (int)r.Element("CandNum") != 0 ? (int)r.Element("CandNum") : 0,
                EventNum = (int)r.Element("EventNum") != 0 ? (int)r.Element("EventNum") : 0,
                EventDate = (string)(r.Element("EventDate")) == string.Empty ?
                            DateTime.Today : (DateTime)(r.Element("EventDate")),
                EventTime = (string)(r.Element("EventTime")) == string.Empty ?
                            DateTime.Now : (DateTime)(r.Element("EventTime")),
                CandFirstName = (string)r.Element("CandFirstName") != null ? (string)r.Element("CandFirstName") : string.Empty,
                CandLastName = (string)r.Element("CandLastName") != null ? (string)r.Element("CandLastName") : string.Empty,
                CandPhone1 = (string)r.Element("CandPhone1") != null ? (string)r.Element("CandPhone1") : string.Empty,
                CandPhone2 = (string)r.Element("CandPhone2") != null ? (string)r.Element("CandPhone2") : string.Empty,
                CandPhone3 = (string)r.Element("CandPhone3") != null ? (string)r.Element("CandPhone3") : string.Empty,
                CandAttach1 = (string)r.Element("CandAttach1") != null ? (string)r.Element("CandAttach1") : string.Empty,
                CandAttach2 = (string)r.Element("CandAttach2") != null ? (string)r.Element("CandAttach2") : string.Empty,
                CandAttach3 = (string)r.Element("CandAttach3") != null ? (string)r.Element("CandAttach3") : string.Empty
            }) as CandidateList
    };
    return req.ToList();
}

catch (Exception ex)
{
    throw ex;
}

2 个答案:

答案 0 :(得分:0)

感谢您整理问题 - 不得不横向滚动有点噩梦(将编辑显示)。

无论如何 - 您的主要问题似乎是您选择Candidates节点的位置:

CandidateList = (from i in input.Root.Element("Candidates").Elements("Candidate") 

问题是linq查询不会产生CandidateList实例。一种方法是将范围构造函数添加到CandidateList类型并将linq查询提供给它。另外 - 我认为input.Root是错误的。

public class CandidateList : List<Candidate>{
  public CandidateList() {}
  public CandidateList(IEnumerable<Candidate> range) : base(range) {}
}
//.. in 'new Request{' block
select new Candidate {
  // ... other members elided
  CandidateList = new CandidateList(
    (from i in r.Element("Candidates").Elements("Candidate") 
    select new Candidate()     
    {   
      //...all the Candidate members
    })
  ) //<-- end of the constructor call
}

在将查询移到构造函数中之后,您还需要从该查询的末尾删除as CandidateList,否则您将获得一个空的CandidateList,或者可能从{ArgumentNullException获取List<T> {1}}基类CandidateList。请注意,我已更改from;因为您希望当前Candidates/Candidate的{​​{1}}个节点由Requests/Request提供。

最后 - r对象的所有属性分配都来自Candidate - 您需要将这些属性更改为r(内部Linq语句的产品)。

答案 1 :(得分:0)

您需要显式实例化CandidateList属性。

var doc = XElement.Load(@"path-to-xml");
var result = doc.Descendants("Request")
    .Select(RequestSelector);

private Request RequestSelector(XElement elem)
{
    var request  = new Request();
    // Fill properties here
    request.Candidates = new CandidateList();
    request.Candidates.AddRange(elem.Descendants("Candidate").Select(CandidateSelector));
    return request;
}

private Candidate CandidateSelector(XElement elem)
{
    var candidate = new Candidate();
    candidate.CandFirstName = elem.Element("CandFirstName").Value;
    // Fill other properties here
    return candidate;
}