简体   繁体   中英

C# How to select all nodes of xml that have matching values

Below is an example of my starting xml and the xml result i'm trying to achieve. What i'm trying to figure out is not how to create the desired xml but how to grab all matches nodes that have the same starting value. For example below, you'll see the xml has apples, there are two nodes with apples. I want to find all those nodes and then create a custom xml afterwards.

How do you loop for all nodes of an xml and then find all results on that same node level that have matching values?

<?xml version="1.0"?>
<results>
    <result>
        <fruit>apples</fruit>
        <price>0</price>
    </result>
    <result>
        <fruit>pears</fruit>
        <price>1</price>
    </result>
    <result>
        <fruit>apples</fruit>
        <price>2</price>
    </result>
</results>



<?xml version="1.0"?>
<results>
    <result>
        <fruit>apples</fruit>
        <prices>
            <price>0</price>
            <price>2</price>
        </prices>
    </result>
    <result>
        <fruit>pears</fruit>
        <prices>
            <price>1</price>
        </prices>
    </result>
</results>

You can accomplish this by using XDocument . Do not forget to import.

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

load document

      XDocument doc = XDocument.Load("C:\\t\\My File2.txt");
  1. Select all result elements
  2. Group by fruit value for example 3 apples 1 pears
  3. Put the result elements from group and add them into an array
  4. Create list that contains the array with the result elements

      List<XElement[]> multipleElements = doc .XPathSelectElements("results/result") .GroupBy(result => result.Element("fruit").Value) .Select(groupContent => groupContent.ToArray()) .ToList(); 

=========== result ===================

 List [0] { apples,apples} 
 List [1] { pear }

XML I tested on:

 <?xml version="1.0"?> <results> <result> <fruit>apples</fruit> <price>0</price> </result> <result> <fruit>pears</fruit> <price>1</price> </result> <result> <fruit>apples</fruit> <price>2</price> </result> </results> 

This VB code creates the desired output. It selects as results and orders them by fruit value, and then a simple loop to create the desired output.

    Dim xe As XElement
    ' to load from a file
    ' Dim yourpath As String = "your path here"
    'xe = XElement.Load(yourpath)

    ' for testing
    xe = <results>
             <result>
                 <fruit>apples</fruit>
                 <price>0</price>
             </result>
             <result>
                 <fruit>pears</fruit>
                 <price>1</price>
             </result>
             <result>
                 <fruit>apples</fruit>
                 <price>2</price>
             </result>
         </results>


    Dim oxe As XElement = <results></results>
    Dim rsltproto As XElement = <result>
                                    <fruit></fruit>
                                    <prices></prices>
                                </result>
    Dim rslt As XElement
    Dim fruit As String
    'select all <result> order by fruit values
    Dim allfruits As IEnumerable(Of XElement) = xe...<result>.OrderBy(Function(el) el.<fruit>.Value)

    'simple loop to create new XML
    For Each el As XElement In allfruits
        If el.<fruit>.Value <> fruit Then
            If rslt IsNot Nothing Then
                oxe.Add(rslt)
            End If
            fruit = el.<fruit>.Value
            rslt = New XElement(rsltproto)
            rslt.<fruit>.Value = fruit
        End If
        rslt.<prices>.LastOrDefault.Add(el.<price>)
    Next
    If rslt IsNot Nothing Then
        oxe.Add(rslt)
    End If


    ' to save file
    ' xe.Save(yourpath)

This is a simple change to Timon's answer above

var doc = XDocument.Load(@"<path>\test.xml");

var fruitPrices = doc.XPathSelectElements("results/result")
        .Select(d => new { 
            Fruit = d.Element("fruit").Value,
            // TODO: parse to int if required
            Price = d.Element("price").Value
        })
        .GroupBy(f => f.Fruit)
        .Select(g => new {Fruit = g.Key, Prices = g.Select(x => x.Price)})
        .ToList();

In LinqPad this gives

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM