C#linq XDoc根据重复的xelement删除子节点

时间:2016-02-10 22:24:28

标签: c# xml linq

我有以下XDocument:

<GetAssetWarrantyResponse>
  <GetAssetWarrantyResult>
    <Faults />
    <Response>
      <DellAsset>
        <AssetParts nil="true" />
        <CountryLookupCode>11</CountryLookupCode>
        <CustomerNumber>100540040</CustomerNumber>
        <IsDuplicate>false</IsDuplicate>
        <ItemClassCode>UI002</ItemClassCode>
        <LocalChannel>05</LocalChannel>
        <MachineDescription>OPTI 3020,TIGRISSFFFBTX</MachineDescription>
        <OrderNumber>aaaaaa</OrderNumber>
        <ParentServiceTag nil="true" />
        <ServiceTag>1234567</ServiceTag>
        <ShipDate>2014-03-21T00:00:00</ShipDate>
        <Warranties>
          <Warranty>
            <EndDate>2022-03-21T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>422-0052</ItemNumber>
            <ServiceLevelCode>D</ServiceLevelCode>
            <ServiceLevelDescription>DirectLine Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2017-03-21T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>984-0092</ItemNumber>
            <ServiceLevelCode>KK</ServiceLevelCode>
            <ServiceLevelDescription>Keep Your Hard Drive Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2017-03-21T23:59:59</EndDate>
            <EntitlementType>EXTENDED</EntitlementType>
            <ItemNumber>939-7358</ItemNumber>
            <ServiceLevelCode>ND</ServiceLevelCode>
            <ServiceLevelDescription>Next Business Day Support</ServiceLevelDescription>
            <ServiceLevelGroup>5</ServiceLevelGroup>
            <ServiceProvider>UNY</ServiceProvider>
            <StartDate>2015-03-22T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2015-03-21T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>939-6868</ItemNumber>
            <ServiceLevelCode>ND</ServiceLevelCode>
            <ServiceLevelDescription>Next Business Day Support</ServiceLevelDescription>
            <ServiceLevelGroup>5</ServiceLevelGroup>
            <ServiceProvider>UNY</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2022-03-24T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>421-9982</ItemNumber>
            <ServiceLevelCode>D</ServiceLevelCode>
            <ServiceLevelDescription>DirectLine Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2022-03-24T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>525-0013</ItemNumber>
            <ServiceLevelCode>D</ServiceLevelCode>
            <ServiceLevelDescription>DirectLine Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2022-03-24T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>422-0008</ItemNumber>
            <ServiceLevelCode>D</ServiceLevelCode>
            <ServiceLevelDescription>DirectLine Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
        </Warranties>
      </DellAsset>
      <DellAsset>
        <AssetParts nil="true" />
        <CountryLookupCode>11</CountryLookupCode>
        <CustomerNumber>100540040</CustomerNumber>
        <IsDuplicate>false</IsDuplicate>
        <ItemClassCode>7M002</ItemClassCode>
        <LocalChannel>05</LocalChannel>
        <MachineDescription>POWEREDGE R720XD, ORCA S PE</MachineDescription>
        <OrderNumber>1846</OrderNumber>
        <ParentServiceTag nil="true" />
        <ServiceTag>8523145</ServiceTag>
        <ShipDate>2013-03-20T00:00:00</ShipDate>
        <Warranties>
          <Warranty>
            <EndDate>2016-03-20T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>936-7263</ItemNumber>
            <ServiceLevelCode>SV</ServiceLevelCode>
            <ServiceLevelDescription>Silver Premium Support</ServiceLevelDescription>
            <ServiceLevelGroup>8</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2013-03-20T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2016-03-20T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>983-6402</ItemNumber>
            <ServiceLevelCode>KK</ServiceLevelCode>
            <ServiceLevelDescription>Keep Your Hard Drive Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2013-03-20T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2016-03-20T23:59:59</EndDate>
            <EntitlementType>EXTENDED</EntitlementType>
            <ItemNumber>936-7243</ItemNumber>
            <ServiceLevelCode>ND</ServiceLevelCode>
            <ServiceLevelDescription>Next Business Day Support</ServiceLevelDescription>
            <ServiceLevelGroup>5</ServiceLevelGroup>
            <ServiceProvider>UNY</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2014-03-20T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>989-2701</ItemNumber>
            <ServiceLevelCode>ND</ServiceLevelCode>
            <ServiceLevelDescription>Next Business Day Support</ServiceLevelDescription>
            <ServiceLevelGroup>5</ServiceLevelGroup>
            <ServiceProvider>UNY</ServiceProvider>
            <StartDate>2013-03-20T00:00:00</StartDate>
          </Warranty>
        </Warranties>
      </DellAsset>
</GetAssetWarrantyResult>

我要做的是删除Warranty节点中Warranties重复XElement的每个ServiceLevelDescription节点。

我尝试编辑的部分示例:

<Warranties>
          <Warranty>
            <EndDate>2022-03-21T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>422-0052</ItemNumber>
            <ServiceLevelCode>D</ServiceLevelCode>
            <ServiceLevelDescription>DirectLine Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2017-03-21T23:59:59</EndDate>
            <EntitlementType>INITIAL</EntitlementType>
            <ItemNumber>984-0092</ItemNumber>
            <ServiceLevelCode>KK</ServiceLevelCode>
            <ServiceLevelDescription>Keep Your Hard Drive Service</ServiceLevelDescription>
            <ServiceLevelGroup>11</ServiceLevelGroup>
            <ServiceProvider>DELL</ServiceProvider>
            <StartDate>2014-03-21T00:00:00</StartDate>
          </Warranty>
          <Warranty>
            <EndDate>2017-03-21T23:59:59</EndDate>
            <EntitlementType>EXTENDED</EntitlementType>
            <ItemNumber>939-7358</ItemNumber>
            <ServiceLevelCode>ND</ServiceLevelCode>
            <ServiceLevelDescription>Next Business Day Support</ServiceLevelDescription>
            <ServiceLevelGroup>5</ServiceLevelGroup>
            <ServiceProvider>UNY</ServiceProvider>
            <StartDate>2015-03-22T00:00:00</StartDate>
          </Warranty>          
        </Warranties>

我尝试了几种变体:

XDocument testing = XDocument.Load(testXMLPath);
testing.Root.Element("Response").Descendants("Warranty")
                .Where(x => (string)x.Element("ServiceLevelDescription") == (string)x.Element("ServiceLevelDescription"))
                .Remove();

var testRemoval = from warranties in testing.Descendants("Request")
                              from warranty in warranties.Descendants()
                              group warranties by warranty.Attribute("Warranty").Value into distinctResult
                              select new
                              {
                                  warr = distinctResult.FirstOrDefault().Attribute("ServiceLevelDescription").Value, value = distinctResult.Key
                              };

可悲的是,这不起作用。

我尝试过:Thisthis - 这是我想要完成的两件最接近的事情

澄清:我只是想根据Warranty父节点中ServiceLevelDescription字段是否重复来删除重复的(Warranties)节点。

注意:此XML来自一个蒸汽。也许我可以在它出现时过滤它

更新:我决定尝试从另一个角度来解决这个问题。也许如果我尝试使用所需的信息重新创建xml,这将有效。

这是我到目前为止所做的:

    var newDocument = new XDocument(new XElement("Machine", xlBaseInfo.Select(z =>
        new XElement("Asset",
            new XElement("Product", z.Product),
            new XElement("OrderNumber", z.OrderNumber),
            new XElement("ServiceTag", z.ServiceTag),
            new XElement("ShipDate", z.ShipDate),
                (new XElement("Warranties", testing.Select(x =>
                    new XElement("Warranty",                        
                        new XElement("Service",
                        new XElement("ServiceDescription", x.Service),
                        new XElement("Provider", x.Provider),
                        new XElement("StartDate", x.StartDate),
                        new XElement("EndDate", x.EndDate),
                        new XElement("Type", x.TypeOfWarranty)
            )))
            //Get unique results here .FirstOrDefualt Does not work
            ))))));

更新2:我发现了这一点,看起来很有希望:

// Return a list of duplicate nodes
            var findDups = from n in testing.Root.Descendants("Warranties")
                           group n by n.Attribute("ServiceLevelDescription").Value into warrantyGroup
                           where warrantyGroup.Count() > 1
                           from eg in warrantyGroup
                           where eg.Attribute("ServiceLevelDescription").Value != "0" //TODO: <--- Condition to check for duplicates
                           select eg;

            // Remove the duplicate nodes
            foreach (XElement element in findDups)
            {
                element.Remove();
            }

OR:

XDocument groupTest = XDocument.Load(testXMLPath);

            groupTest.Root.Elements("Warranties")
                .SelectMany(s => s.Elements("Warranty")
                .GroupBy(g => g.Attribute("ServiceLevelDescription").Value)
                .SelectMany(m => m.Skip(1))).Remove();

2 个答案:

答案 0 :(得分:1)

我想首先说,如果你不得不做这种过滤,整体设计看起来有缺陷。在说,我不确定你在做什么的背景,所以无论如何这是一个解决方案。

这应该有用。

document.Root.DescendantsAndSelf("Warranties")
    .SelectMany(n =>
        n.Elements("Warranty")
            .GroupBy(g => g.Element("ServiceLevelDescription").Value)
            .Where(g => g.Count() > 1)
            .SelectMany(g => g))
    .Remove();  

以下是按上述查询执行顺序排列的内容。如果你不能跟随,请随便。

  1. 查找每个<Warranties />节点及其子节点,
  2. <Warranty />对每个<Warranties />节点中的<ServiceLevelDescription />个孩子进行分组,
  3. 丢弃任何唯一节点并仅保留重复
  4. 将令人难以置信的嵌套XElements列表展平为一个IEnumerable,然后执行.Remove()。
  5. 我最初获取<Warranties />个节点而不是<Warranty />个节点,因为我希望将每组<Warranty />个节点组合在一起,以便仅从其父<Warranties />中删除重复项节点

    以下是原始输入的输出:

    <GetAssetWarrantyResponse>
      <GetAssetWarrantyResult>
        <Faults />
        <Response>
          <DellAsset>
            <AssetParts nil="true" />
            <CountryLookupCode>11</CountryLookupCode>
            <CustomerNumber>100540040</CustomerNumber>
            <IsDuplicate>false</IsDuplicate>
            <ItemClassCode>UI002</ItemClassCode>
            <LocalChannel>05</LocalChannel>
            <MachineDescription>OPTI 3020,TIGRISSFFFBTX</MachineDescription>
            <OrderNumber>aaaaaa</OrderNumber>
            <ParentServiceTag nil="true" />
            <ServiceTag>1234567</ServiceTag>
            <ShipDate>2014-03-21T00:00:00</ShipDate>
            <Warranties>
              <Warranty>
                <EndDate>2017-03-21T23:59:59</EndDate>
                <EntitlementType>INITIAL</EntitlementType>
                <ItemNumber>984-0092</ItemNumber>
                <ServiceLevelCode>KK</ServiceLevelCode>
                <ServiceLevelDescription>Keep Your Hard Drive Service</ServiceLevelDescription>
                <ServiceLevelGroup>11</ServiceLevelGroup>
                <ServiceProvider>DELL</ServiceProvider>
                <StartDate>2014-03-21T00:00:00</StartDate>
              </Warranty>
            </Warranties>
          </DellAsset>
          <DellAsset>
            <AssetParts nil="true" />
            <CountryLookupCode>11</CountryLookupCode>
            <CustomerNumber>100540040</CustomerNumber>
            <IsDuplicate>false</IsDuplicate>
            <ItemClassCode>7M002</ItemClassCode>
            <LocalChannel>05</LocalChannel>
            <MachineDescription>POWEREDGE R720XD, ORCA S PE</MachineDescription>
            <OrderNumber>1846</OrderNumber>
            <ParentServiceTag nil="true" />
            <ServiceTag>8523145</ServiceTag>
            <ShipDate>2013-03-20T00:00:00</ShipDate>
            <Warranties>
              <Warranty>
                <EndDate>2016-03-20T23:59:59</EndDate>
                <EntitlementType>INITIAL</EntitlementType>
                <ItemNumber>936-7263</ItemNumber>
                <ServiceLevelCode>SV</ServiceLevelCode>
                <ServiceLevelDescription>Silver Premium Support</ServiceLevelDescription>
                <ServiceLevelGroup>8</ServiceLevelGroup>
                <ServiceProvider>DELL</ServiceProvider>
                <StartDate>2013-03-20T00:00:00</StartDate>
              </Warranty>
              <Warranty>
                <EndDate>2016-03-20T23:59:59</EndDate>
                <EntitlementType>INITIAL</EntitlementType>
                <ItemNumber>983-6402</ItemNumber>
                <ServiceLevelCode>KK</ServiceLevelCode>
                <ServiceLevelDescription>Keep Your Hard Drive Service</ServiceLevelDescription>
                <ServiceLevelGroup>11</ServiceLevelGroup>
                <ServiceProvider>DELL</ServiceProvider>
                <StartDate>2013-03-20T00:00:00</StartDate>
              </Warranty>
            </Warranties>
          </DellAsset>
        </Response>
      </GetAssetWarrantyResult>
    </GetAssetWarrantyResponse>
    

    这是你期望的吗?

答案 1 :(得分:0)

你可以尝试像遍历文档和删除所有的双重内容,我想你可以在linq中编写一个子查询,而不是每个都使用

 var info=testing.Root.Element("Response").Descendants("Warranty");
    foreach (var qry in info)
    {
        if(qry.Slect(x => (string)x.Element("ServiceLevelDescription")).Count()>1)
        {
             qry.Remove();
        }
    }