0

This might be the simplest question for that i appologise. This is part of my xml. What i want to get is the attribute "Value" based on another attribute "ItemOID". IE when ItemOID="I_MEDIC_HISTORY_INDICATION" what is the value.

<FormData FormOID="F_NEUROLOGICAL_V20" OpenClinica:Version="V2.0" OpenClinica:Status="initial data entry">
    <ItemGroupData ItemGroupOID="IG_NEURO_UNGROUPED" ItemGroupRepeatKey="1" TransactionType="Insert">
        <ItemData ItemOID="I_NEURO_NEURO_TENDONAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_TENDON" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_GAITAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_GAIT" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_COORDINATEAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_COORDINATE" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_SENSORYAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_SENSORY" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_MUSCLETONEAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_MUSCLETONE" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_MOTORAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_MOTOR" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_CRANIALAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_CRANIAL" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_SPEECHAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_SPEECH" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_BEHAVEAB" Value="abnormal" />
        <ItemData ItemOID="I_NEURO_NEURO_BEHAVE" Value="0" />
        <ItemData ItemOID="I_NEURO_NEURO_APPEARAB" Value="" />
        <ItemData ItemOID="I_NEURO_NEURO_APPEAR" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_NORMAL" Value="1" />
        <ItemData ItemOID="I_NEURO_NEURO_DATE" Value="2014-10-10" />
    </ItemGroupData>
</FormData>

This is my code. As you can tell i am a bit stuck.

string neuroExamPath = "//oc:FormData[@FormOID='F_NEUROLOGICAL_V20']/oc:ItemGroupData/oc:ItemData";
var neuroExamList = doc.XPathSelectElements(neuroExamPath, nsmgr).Reverse();

foreach (var neuroExamElement in neuroExamList)
{
    var patrow = patDt.NewRow();
    var I_NEURO_NEURO_NORMAL = neuroExamElement.Attribute("Value").Value;
    patrow["Neuro_normal"] = I_NEURO_NEURO_NORMAL;
    var I_NEURO_NEURO_APPEAR = neuroExamElement.Attribute("Value").Value;
    patrow["Neuro_appear"] = I_NEURO_NEURO_APPEAR;
    var I_NEURO_NEURO_APPEARAB = neuroExamElement.Attribute("Value").Value;
    patrow["Neuro_appearab"] = I_NEURO_NEURO_APPEARAB;

    patDt.Rows.Add(patrow);
}

As you can tell it will iterate all the attribute Value all the time. However i need var I_NEURO_NEURO_NORMAL = neuroExamElement.Attribute("Value").Value; line to have a condition where ItemOID="I_NEURO_NEURO_NORMAL" and so on. So i can put one attribute at a time into a datatable. Please help. Thank you.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
user3276223
  • 59
  • 1
  • 8
  • Please put more effort into formatting your code in future questions. Compare how you posted it with the current version, and next time use the preview to make sure it's indented appropriate before submission. The easier you make it for people to read and understand your question, the more/better answers you're likely to get. – Jon Skeet Oct 16 '14 at 09:33
  • Sorry Jon. Newbie at posting. Cheers. – user3276223 Oct 16 '14 at 09:35

1 Answers1

1

It looks to me like you want a new row for each ItemGroupData element, not each ItemData element. I would expect something like:

foreach (var itemGroup in doc.Root.Elements("ItemGroupData"))
{
    var row = patDt.NewRow();
    row["Neuro_normal"] = itemGroup.ExtractValue("I_NEURO_NEURO_NORMAL");
    row["Neuro_appear"] = itemGroup.ExtractValue("I_NEURO_NEURO_APPEAR");
    row["Neuro_appearab"] = itemGroup.ExtractValue("I_NEURO_NEURO_APPEARAB");
    patDt.Rows.Add(row);
}

which uses a new extension method:

public static string ExtractValue(this XElement parent, string oid)
{
    return parent.Elements("ItemData")
                 .Where(x => x.Attribute("ItemOID").Value == oid)
                 .First()
                 .Attribute("Value")
                 .Value;
}

Alternatively, if you're extracting a lot of the attributes, you could build a dictionary:

var values = itemGroup.Elements("ItemData")
                      .ToDictionary(x => x.Attribute("ItemOID").Value,
                                    x => x.Attribute("Value").Value);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thats a very elegant and amazing solution. Is there anyway to add this Xpath //oc:FormData[@FormOID='F_NEUROLOGICAL_V20'] to the query? I want to wittle it down based on FormData as well. This is a huge xml with many ie – user3276223 Oct 16 '14 at 10:51
  • @user3276223: Well I wouldn't use XPath for that - I'd use `doc.Descendants(ns + "FormData").Where(x => x.Attribute("FormOID").Value == "F_NEUROLOGICAL_V20")` where `ns` is the suitable namespace (which is what I assume `oc` is). You certainly *can* use XPath instead, but I prefer to avoid embedding one language within another if I can help it. – Jon Skeet Oct 16 '14 at 10:56