简体   繁体   中英

c# Parse XML and store nodes to grid

This is the XML I get from a request:

<ODM xmlns:.....>
    <Data DID="Mdid">
         <SubjectData SubjectKey="1">
               <SRef Location="Loc1"/>
               <SEventData SEventID="SID1">
                    <FormData FormID="FID1">
                          <ItemGroupData ItemGroupID="IGID1">
                                <ItemData ItemID="IID1" IsNull="Yes"/>
                                <ItemData ItemID="IID2" IsNull="Yes"/>
                                <ItemData ItemID="IID3" IsNull="Yes"/>
                                <ItemData ItemID="IID4" Value="cvs"/>
                          </ItemGroupData>
                    </FormData>
                </SEventData>
          </SubjectData>
     </Data>
     <Data DID="Zdid">
           <SubjectData SubjectKey="2">
               <SRef Location="Loc2"/>
               <SEventData SEventID="SID2">
                    <FormData FormID="FID2">
                          <ItemGroupData ItemGroupID="IGID2">
                                <ItemData ItemID="IID11" Value="xcs"/>
                                <ItemData ItemID="IID12" IsNull="Yes"/>
                                <ItemData ItemID="IID13" IsNull="Yes"/>
                                <ItemData ItemID="IID14" Value="zfv"/>
                          </ItemGroupData>
                    </FormData>
                </SEventData>
          </SubjectData>
     </Data>
          ........
</ODM>

How I can store the Items and their Values in a grid from specific Data , SubjectData , SEventData , FormData , ItemGroupData or ItemData ?

This is what I have tried for ItemData but it returns null :

var xdoc = XDocument.Parse(response.RawXMLString());

var items = xdoc.Descendants("ItemData")
           .ToDictionary(i => (string)i.Attribute("ItemID"),
                         i => (string)i.Attribute("Value"));

Example

Items of "Mdid" Data (will be the same for SubjectKey == 1, SEventID = "SID1" etc. But Items of "Zdid" Data will be diferrent because it will probably contain different ItemData ):

 ItemID    |    IsNull   |  Value
  IID1     |      Yes    |
  IID2     |      Yes    |
             ......

EDIT

Both solutions unfortunately didn't work... In case it helps here is a sample xml I am working on: link

Based on the discussion in the comments, this code will parse the ItemData elements into a list, but will lost the context of whether they came from a Mdid or Zdid section:

First a class to hold the item data:

public class ItemData
{
    public string ItemID { get; set; }
    public string IsNull { get; set; }
    public string Value { get; set; }
}

And the Linq to process the XML:

var items = xdoc
    .Descendants("Data")
    .Where(d => d.Attribute("DID").Value == "Mdid") //These lines can be added
    .Descendants("ItemData")                        //to filter if you need them
   .Select(i => new ItemData
   {
       ItemID = (string)i.Attribute("ItemID"),
       IsNull = (string)i.Attribute("IsNull"),
       Value = (string)i.Attribute("Value")
   }); 

In case you need to include the namespace, this is how you do it:

XNamespace ns = "http://www.cdisc.org/ns/odm/v1.3";

And then prefix the names with `ns. For example:

.Descendants(ns+"ItemData") 

If it is failing you may have more the one ItemData with same value. Try following :

           XDocument doc = XDocument.Load(FILENAME);

            Dictionary<string, string> items = doc.Descendants().Where(x => x.Name.LocalName == "ItemData")
                .GroupBy(x => (string)x.Attribute("ItemOID"), y => y.Attribute("IsNull") != null ? "Null" : (string)y.Attribute("Value"))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

            //if above fails tgry following
            Dictionary<string, List<string>> items2 = doc.Descendants().Where(x => x.Name.LocalName == "ItemData")
                .GroupBy(x => (string)x.Attribute("ItemOID"), y => y.Attribute("IsNull") != null ? "Null" : (string)y.Attribute("Value"))
                .ToDictionary(x => x.Key, y => y.ToList());

            //or use two level dictionary
            Dictionary<int, Dictionary<string, string>> items3 = doc.Descendants().Where(x => x.Name.LocalName == "SubjectData")
                .GroupBy(x => (int)x.Attribute("SubjectKey"), y => y.Descendants().Where(z => z.Name.LocalName == "ItemData")
                    .GroupBy(a => (string)a.Attribute("ItemOID"), b => b.Attribute("IsNull") != null ? "Null" : (string)b.Attribute("Value"))
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

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