0

Just got into a new xml issue I'm little stuck with. Maybe somebody can push me into the right direction :)

I have an XML looking like this:

<import xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///XXXXXXXXX/TraumaSchema.xsd">
    <creationDate>2016-10-18</creationDate>
    <hospitalCode>XXXXXXXXXXXX</hospitalCode>
    <importCasesWithErrors>0</importCasesWithErrors>
    <caseState>1</caseState>
    <caseList>
        <case>
            <patientCode>XXXXXXXXXXX</patientCode>
            <internalPatientId>XXXXXXXXXXXXXXX</internalPatientId>
            <masterData>
                <patient>
                    <age/>
                    <sex>1</sex>
                    <asa>1</asa>
                </patient>
                <accident>
                    <cause>1</cause>
                    <trauma>1</trauma>
                    <dateTime>
                        <date>2016-05-15</date>
                        <time>01:30:00</time>
                    </dateTime>
                </accident>
            </masterData>
            <preClinicalData>
                <alarm>
                    <date>2016-05-15</date>
                    <time>02:00:00</time>
                </alarm>
                <arrival>
                    <date>2016-05-15</date>
                    <time>01:30:00</time>
                </arrival>
                <departure>
                    <date>2016-05-15</date>
                    <time/>
                </departure>
                <vitalSign>
                    <capnometry>0</capnometry>
                    <systolicBloodPressure>
                        <mmHg>140</mmHg>
                    </systolicBloodPressure>
                    <heartRate>
                        <perMinute>130</perMinute>
                    </heartRate>
                    <respiratoryRate>
                        <perMinute>20</perMinute>
                    </respiratoryRate>
                    <oxygenSaturation>
                        <percent>97</percent>
                    </oxygenSaturation>
                </vitalSign>
            ....
            ....
            ....
        </case>
        <case>
            ....
            ....
            ....

The XML is quite big and two things are important to know. There is an element "caseList" which contains a variable number of cases -> "case". Each "case" consists of many other elements. The Element in focus is "patientCode" which is contained in any case-group.

What I need to achieve is to get this parent element "patientCode" starting from any possible child node.

I do not know from where in the hierarchy I have to start. The only thing I know is that I need to get the this particular parent.

Does anybody have an idea how to achieve this?

Any help is very appreciated.

kind regards Sandro

Martin Felber
  • 121
  • 17
  • Load the xml in an XDocument. Then have look at the accepted answer here http://stackoverflow.com/questions/451950/get-the-xpath-to-an-xelement . Then after you get the path to the current element, search for the parent and get only the part you need. – Lidaranis Oct 21 '16 at 09:07
  • noticed that certain text was not written in my queston text -> corrected Thank you Lidaranis, but this is not working for me. I get a huge list of path's but still I have the problem that I do not know where the starting piunt would be. please have again a look at my question – Martin Felber Oct 21 '16 at 09:41
  • Let me know if i understand this. You want to search for the patientCode based on one of the child elements of the case element. For example get the pacient code where oxygenSaturation/percent == 97, but the node on which you base your search(here oxygenSaturation/percent) is dynamic. Am i on the right track? – Lidaranis Oct 21 '16 at 10:45
  • yes exactly. The XML is generated (serialization) so I cannot go another way of xml generation. For better understanding this maybe would be helpful: the use case is that I validate the xml against an xsd. I have written an application that shows the validation errors. Double click on a error will mark the relevant element which caused the error in a richtext box. I need to show the user the patientCode which belongs to the selected element (node). this information is located in the patientCode element in each case. So you're absolutely right :) – Martin Felber Oct 21 '16 at 10:55
  • The application should be written then against the serialized classes not the xml file. You could add a private property to each class that points to parent class. Then run a utility to fill in parent after serialization is performed. Private property are ignored by serialization. – jdweng Oct 21 '16 at 11:01
  • @jdweng you are right but since he needs this for validation, if the xml is wrong the deserialization will fail. Anyway, could you provide us with an example on how does your validation error look like? I mean, what details do you have access to? that should give us a starting point. – Lidaranis Oct 21 '16 at 11:03
  • The code is simple. First add a parent to each class that requires a parent as a private property. Then after serialization is performed start at root class and put parent value into each child. Span down tree until all the parent properties are set. – jdweng Oct 21 '16 at 11:38

2 Answers2

0

Try code like this. It shouldn't be necessary to get parent if the code is structured properly

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication21
{
    class Program
    {
        const string FILEName = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILEName);

            XElement caseList = doc.Descendants().Where(x => x.Name.LocalName == "caseList").FirstOrDefault();
            XNamespace ns = caseList.GetDefaultNamespace();

            var results = caseList.Descendants(ns + "case").Select(x => new {
                masterData = x.Descendants(ns + "masterData").Select(y => new {
                    age = y.Descendants(ns + "age").Select(z => z.IsEmpty  ? null : (int?)z).FirstOrDefault(),
                    sex = (int?)y.Descendants(ns + "sex").FirstOrDefault(),
                    asa = (int?)y.Descendants(ns + "asa").FirstOrDefault(),
                    cause = (int?)y.Descendants(ns + "cause").FirstOrDefault(),
                    trauma = (int?)y.Descendants(ns + "trauma").FirstOrDefault(),
                    date = (DateTime) y.Descendants(ns + "date").FirstOrDefault() + ((DateTime)(y.Descendants(ns + "time").FirstOrDefault())).TimeOfDay,
                }).FirstOrDefault(),
                preClinicalData = x.Descendants(ns + "masterData").Select(y => new {
                    alarm = (DateTime) y.Descendants(ns + "date").FirstOrDefault() + ((DateTime)(y.Descendants(ns + "time").FirstOrDefault())).TimeOfDay,
                    arrival = (DateTime)y.Descendants(ns + "date").FirstOrDefault() + ((DateTime)(y.Descendants(ns + "time").FirstOrDefault())).TimeOfDay,
                    departure = (DateTime)y.Descendants(ns + "date").FirstOrDefault() + ((DateTime)(y.Descendants(ns + "time").FirstOrDefault())).TimeOfDay,
                    capnometry = (int?)x.Descendants(ns + "capnometry").FirstOrDefault(),
                    mmHg = (int?)x.Descendants(ns + "mmHg").FirstOrDefault(),
                    heartRate = (int?)x.Descendants(ns + "heartRate").FirstOrDefault(),
                    respiratoryRate = (int?)x.Descendants(ns + "respiratoryRate").FirstOrDefault(),
                    oxygenSaturation = (int?)x.Descendants(ns + "oxygenSaturation").FirstOrDefault(),                    
                }).FirstOrDefault()
            }).ToList();


        }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Thank you very much jdweng, but unfortunately I can't use this kind of implementation. The XML is created by serialization of a complex structure of classes. Depending on the data, some XML-Elements will not be serialized etc. So the content and the structure is not always the same. – Martin Felber Oct 21 '16 at 10:46
0

UPDATE

Ok, I had another idea:

I know which node is selected. With this I can get the path to the root like this

var element = doc.Descendants(GetSelectedNode()).First();
var names = element.AncestorsAndSelf()
             .Reverse()
             .Skip(1) // Skip the root
             .Select(x => x.Name);
var joined = string.Join("/", names);

joined now contains the path to the root like this for example:

caseList/case/preClinicalData/therapy/catecholamines (-> a selected node)

The problem now is that I need to follow up the path to get the element "patientCode" right below the "case"-node.

How can I follow the retrieved path to get the relevant element data by using xPath for example?

Martin Felber
  • 121
  • 17