Linq to XML - 元素项的动态计数

时间:2012-12-27 20:38:13

标签: c# xml linq

我的目标

我需要根据Placement_ID和Fill_ID的组合创建一个动态次数出现在我的文档中的XElement。如果我的对象列表中的记录与另一个记录具有相同的Placement_ID,我想在前一个记录下附加另一个填充XElement,其中包含不同的Fll_ID。示例如下:

<envelope ack="entity" transaction="multi">
  <auth>
        <user>TM_DEV</user>
        <session>session1</session>
  </auth>
  <Trading op="createOrder, pretradeCpl, sendToTrading,createPlacement, createFill" id="os1">
        <order op="create" id="test1234">
              <scenario id="sample" />
              <execBroker>BEAR</execBroker>
              <ticker>MSFT</ticker>
              <trader>TM_DEV</trader>
              <instruction>LIM</instruction>
              <limitPrice>85</limitPrice>
              <transType>BUYL</transType>
              <orderDuration>GTC</orderDuration>
              <tradeDate>
              </tradeDate>
              <settleDate>
              </settleDate>
              <allocation id="" op="create">
                    <acctCd>tstacc00006</acctCd>
                    <targetQty>300</targetQty>
                    <specialInst />
              </allocation>
              <placement id="Place1" op="create">
                    <execBroker>BEAR</execBroker>
                    <placeQty>300</placeQty>
                    <fill id="fill1" op="create">
                          <fillQty>150</fillQty>
                          <fillPrice>43</fillPrice>
                    </fill>
                    <fill id="fill2" op="create">
                          <fillQty>150</fillQty>
                          <fillPrice>44</fillPrice>
                    </fill>
              </placement>
        </order>
  </Trading>

我的进步

我到目前为止编写的代码查询列表对象并为每一行生成一个新订单。我需要能够通过Placement_ID对列表进行分组,如果它们是两行具有相同的Placement_ID,那么我希望它能够编写多个Fill元素。否则,如果没有重复的Placement_ID,那么列表中每行数据将有1个订单,1个展示位置和1个填充。

XDocument doc = new XDocument(
           new XDeclaration("1.0", "UTF-8", "yes"),
          new XElement("envelope",
          new XAttribute("ack", "entity"),
          new XAttribute("transaction", "multi"),
           new XElement("auth",
           new XElement("user", "TM_DEV"),
           new XElement("session", "session1")),
           new XElement("trading",
               new XAttribute("op", "createOrder, pretradeCpl, sendToTrading, createPlacement, createFill"),
               new XAttribute("id", "os1"),
           from t in trades.ToList()
           select new XElement("order",
                   new XAttribute("op", "create"),
                   new XAttribute("id", DateTime.Now.ToString("yyMMddHHmmssfff") + t.OrderId),
                   new XElement("Scenario",
                       new XAttribute("id", "sample")),
                   new XElement("execBroker", t.ExecBrkID),
                   new XElement("ticker", t.Ticker),
                   new XElement("sedol", t.Sedol),
                   new XElement("Trader", "TM_DEV"),
                   new XElement("transType", t.TransType),
                   new XElement("orderDuration", "GTC"),
                   new XElement("tradeDate", ""),
                   new XElement("settleDate", ""),
                   new XElement("allocation",
                       new XAttribute("id", ""),
                       new XAttribute("op", "create"),
                       new XElement("acctCd", t.Account),
                       new XElement("targetQty", t.TargetQty),
                       new XElement("specialInst", "who to settle with")),
                   new XElement("placement",
                       new XAttribute("op", "create"),
                       new XAttribute("id", t.PlacementId),
                       new XElement("execBroker", t.ExecBrkID),
                       new XElement("placeQty", t.ExecQty),
                       new XElement("fill",
                           new XAttribute("id", t.FillId),
                           new XAttribute("op", "create"),
                       new XElement("fillQty", t.ExecQty),
                       new XElement("fillPrice", t.ExecPrice)))))));

更新

我使用您的建议在我的更新中细分了示例。现在我收到“文档格式不正确”的错误。

using (XmlWriter xw = XmlWriter.Create(s, xws)){


XElement order = new XElement("order");
var groupedOrders = trades.GroupBy(o => o.OrderId);

foreach (var groupie in groupedOrders)
{
    int n = 1;
    XElement root = new XElement("placement",
                    from g in groupie
                       select new XElement("t",
                                new XAttribute("op", "create"),
                              new XAttribute("id", g.Ticker)));                    
    foreach (var fill in groupie)
    {
        XElement newFillElement = new XElement("fill" + n,
                                    new XAttribute("id", fill.PlacementId),
                                   new XAttribute("op", "create"),
                                    new XElement("fillQty", fill.ExecQty),
                                    new XElement("fillPrice", fill.ExecPrice));
        root.Add(newFillElement);
        n++;   
    }

    order.Add(root);
}

XDocument doc = new XDocument(
                    new XDeclaration("1.0", "UTF-8", "yes"), order);
doc.Save(xw);

}

2 个答案:

答案 0 :(得分:1)

乍一看,你似乎试图在一次通过中做太多。我认为创建基础文档很好,但如果你需要有条件地添加填充,那么你需要一个不同的策略。

我建议您在循环使用之前使用LINQ按Placement_ID对订单进行分组。这将确保组元素具有相同的Placement_ID - 并允许您添加适当数量的fills

一些伪代码:

var groupedOrders = listOfOrders.GroupBy(o => o.Placement_ID);
foreach (var group in groupedOrders)
{
    //Create document, but don't add any fills
    XDocument doc = new XDocument(...)

    int n = 1;
    foreach (var fill in group)
    {
        //Same structure as before, just a separate element
        XElement newFillElement = new XElement("fill" + n, ...);

        //Add as last element to existing doc
        doc.Add(newFillElement);

        n++
    }
}

参考文献:
101 LINQ Examples, LINQ - Grouping Operators
Adding, Updating, and Deleting Data in XML

答案 1 :(得分:0)

你能创建xml构建的OUTSIDE关系吗?那么从那里重建xml?你似乎只是说这可能更容易。您可以创建一个通用列表,它是xml元素和属性中所需的所有数据。将xml转储到其中,然后将其导出。添加动态扩展的东西,这将是一组规则。使用Linq to XML将xml查询到通用列表中。

我不会像你的例子那样做一些激烈的事情,因为你只需要理解一个概念。您可以直接在“后代”方法中进行计数和其他操作,但我通常更喜欢将内容放到列表中然后我知道我有什么

例如

XML:

<Orders>
  <Person Name="Brett">
    <Order Name="thing"/>
  </Person>
  <Person Name="Joe">
   <Order Name="thing"/>
   <Order Name="thing2" />
  </Person>
</Orders>

C#示例:

using System;
using System.Linq;
using System.Xml.Linq;

namespace TestLinqXml
{
    public class Program
    {
        private static void Main(string[] args)
        {
            // load original doc
            var doc = XDocument.Load(@"C:\TestCode\TestLinqXml\TestLinqXml\XML\Orders.xml");

            // query it with Linq using lambda patterns.
            var list = doc.Descendants("Person")
                          .Select(x => new 
                                  // expand descendents out into a class I make up below by declarining new and defining object
                                  {
                                      Name = x.Attribute("Name").Value,
                                      OrderCount = x.Descendants("Order").Count()
                                  }
                );

            // recreate the new doc
            XDocument newdoc = new XDocument(
                new XDeclaration("1.0", "UTF-8", "yes"),
                new XElement("person",
                             list.Select(n =>
                                         new XElement(n.Name,
                                                      new XAttribute("OrderCount", n.OrderCount)
                                             ))
                    )
                );

            // save it
            newdoc.Save(@"C:\TestCode\TestLinqXml\TestLinqXml\XML\output.xml");
        }
    }
}