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

本文关键字:动态 元素 to XML Linq | 更新日期: 2023-09-27 17:49:37

My Goal

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

<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那么我希望它写多个填充元素。否则,如果没有重复的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);

}

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

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

我建议您在循环之前使用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示例,LINQ -分组运算符
在XML中添加、更新和删除数据

能否在xml构建之外创建关系,然后从中重建xml ?听你这么说似乎更容易些。您可以创建一个通用列表,其中包含您在xml中需要的元素和属性的所有数据。将xml转储到其中,然后将其导出。加上动态扩展的东西,也就是一组规则。使用Linq to XML将XML查询到泛型列表。

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

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");
        }
    }
}