Search code examples
c#xmlsoapxpathenvelope

How to handle this XML response (SOAP:Envelope) correctly?


i created a Web-request to the HP Service Manager in our company, to collecting some data. The result is:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Body>
      <RetrieveSuegChangeListResponse message="Success" returnCode="0" schemaRevisionDate="2015-04-22" schemaRevisionLevel="0" status="SUCCESS" xsi:schemaLocation="http://schemas.hp.com/SM/7 http://servicemanager-ws.intranet.example.com:12345/SM/7/SuegChange.xsd" xmlns="http://schemas.hp.com/SM/7" xmlns:cmn="http://schemas.hp.com/SM/7/Common" xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         <instance query="" recordid="CM00088641 - Server: Migration of the SSH-HOP" uniquequery="header,number=&quot;CM00088641&quot;">
            <header type="Structure">
               <Number type="String">CM00088641</Number>
               <PlannedStart type="DateTime">2015-07-06T06:00:00+00:00</PlannedStart>
               <PlannedEnd type="DateTime">2015-07-06T18:00:00+00:00</PlannedEnd>
               <Title type="String">Server: Migration of the SSH-HOP</Title>
            </header>
            <middle type="Structure">
               <AffectedCi type="Array">
                  <AffectedCi type="String">SERVER1</AffectedCi>
                  <AffectedCi type="String">SERVER2</AffectedCi>
                  <AffectedCi type="String">SERVER3</AffectedCi>
               </AffectedCi>
            </middle>
         </instance>
      </RetrieveSuegChangeListResponse>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

now I'm trying to get the Information from this result, but I'm get in trouble with following C# code:

public static string gettextfromWebserviceChange()
        {
            #region suchen im XML
            XmlDocument  objReturn = new XmlDocument();
            string result = @"<SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"">
                                       <SOAP-ENV:Body>
                                          <RetrieveSuegChangeListResponse message=""Success"" returnCode=""0"" schemaRevisionDate=""2015-04-22"" schemaRevisionLevel=""0"" status=""SUCCESS"" xsi:schemaLocation=""http://schemas.hp.com/SM/7 http://servicemanager-ws.intranet.example.com:12345/SM/7/SuegChange.xsd"" xmlns=""http://schemas.hp.com/SM/7"" xmlns:cmn=""http://schemas.hp.com/SM/7/Common"" xmlns:xmime=""http://www.w3.org/2005/05/xmlmime"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
                                             <instance query="" recordid=""CM00088641 - Server: Migration of the SSH-HOP"" uniquequery=""header,number=&quot;CM00088641&quot;"">
                                                <header type=""Structure"">
                                                   <Number type=""String"">CM00088641</Number>
                                                   <PlannedStart type=""DateTime"">2015-07-06T06:00:00+00:00</PlannedStart>
                                                   <PlannedEnd type=""DateTime"">2015-07-06T18:00:00+00:00</PlannedEnd>
                                                   <Title type=""String"">Server: Migration of the SSH-HOP</Title>
                                                </header>
                                                <middle type=""Structure"">
                                                   <AffectedCi type=""Array"">
                                                      <AffectedCi type=""String"">SERVER1</AffectedCi>
                                                      <AffectedCi type=""String"">SERVER2</AffectedCi>
                                                      <AffectedCi type=""String"">SERVER3</AffectedCi>
                                                   </AffectedCi>
                                                </middle>
                                             </instance>
                                          </RetrieveSuegChangeListResponse>
                                       </SOAP-ENV:Body>
                                    </SOAP-ENV:Envelope>";
                    objReturn.LoadXml(result);
                    
                    List<String> ListAffectedCi = new List<string>();
                    String Descriptiontxt = "";
                    String ChangeStartDate = "";
                    String ChangeEndDate = "";
                    StringBuilder builder = new StringBuilder();


                    //ToDo: which is the right NameSpace!!!!!!!!!
                    XmlNamespaceManager namespaces = new XmlNamespaceManager(objReturn.NameTable);
                    namespaces.AddNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
                    //XmlNode idNode = doc.SelectSingleNode("/My_RootNode/ns:id", namespaces);

                    XmlNodeList xnList = objReturn.GetElementsByTagName("header");
                    foreach (XmlNode xn in xnList)
                    {
                        ChangeStartDate = xn["PlannedStart"].InnerText;
                        ChangeEndDate = xn["PlannedEnd"].InnerText;
                        Descriptiontxt = xn["Title"].InnerText.Trim();
                    }

                    XmlNodeList xnList2 = objReturn.GetElementsByTagName("AffectedCi");
                    int i = 1;// xnList2.Count;
                    foreach (XmlNode xn in xnList2)
                    {
                            // here i'm get in trouble...
                            ListAffectedCi.Add(xn["AffectedCi"].InnerText);

                        
                    }


            #endregion
            #region zusammenbau des strings
                        /////////////////

                        // Append a string to the StringBuilder and then another line break.
                        builder.Append("<b>Title :</b> " + Descriptiontxt + "<br />");
                        builder.Append("<b>Resource :</b> " + String.Join(", ", ListAffectedCi) + "<br />");
                        DateTime _ChangeStartDate = DateTime.Parse(ChangeStartDate, null, System.Globalization.DateTimeStyles.RoundtripKind);
                        DateTime _ChangeEndDate = DateTime.Parse(ChangeEndDate, null, System.Globalization.DateTimeStyles.RoundtripKind);
                        TimeSpan span = _ChangeEndDate.Subtract ( _ChangeStartDate );

                        //"yyyy-MM-ddTHH:mm:ss.fff"
                        builder.Append("<b>Dauer :</b> " + _ChangeStartDate.ToString("dd.MM.yyyy HH:mm:ss") + "    -    " + " " + _ChangeEndDate.ToString("dd.MM.yyyy HH:mm:ss") + "<br />");
                        builder.Append("<b>Zeitspanne :</b> " + span.Days + " Tage und " + span.Hours + " Stunden.<br />");
                        //builder.Append("<dl><dt><b>Zeitspanne :</b></dt><dd>" + span.Days + " Tage</dd><dd>" + span.Hours + " Stunden</dd><dd>" + span.Minutes + " Minuten</dd><dd>" + span.Seconds + " Sekunden</dd><dd>" + span.Ticks + " Ticks</dd></dl>");

#endregion

            return builder.ToString();
        }

My problem is, that i receive a list with 4 AffectedCIs... 3 are filled, and one is null, which create a unhandled NullReferenceException. Do anyone know how it is possible to handle this XML well?

also i tried out with Xpath... but I'm to stupid to find the correct namespace for that XML... Elsewere i could go directly to the AffectedCI path to get the correct amount of CIs...

I hope someone can help me! Thank you in advance, Best regards


Solution

  • If you're not wedded to XmlDocument, LINQ to XML is a far nicer solution to this:

    XNamespace ns = "http://schemas.hp.com/SM/7";
    
    var doc = XDocument.Parse(result);
    
    var header = doc.Descendants(ns + "header").Single();
    
    var start = (DateTime)header.Element(ns + "PlannedStart");
    var end = (DateTime)header.Element(ns + "PlannedEnd");
    var description = (string)header.Element(ns + "Title");
    
    var affectedCis = doc.Descendants(ns + "AffectedCi")
        .Where(e => (string)e.Attribute("type") == "String")
        .Select(e => e.Value)
        .ToList();