0

I have been digging through every example I can find related to Xpath and XML parsing. I can't find a close enough example to the XML I have to deal with that makes any sense to me. I am having an extremely difficult time wrapping my head around Xpath in particular but also XML parsing in a more general sense. The complexity of the file I'm working with is not making it easier to understand.

I have an XML file coming from a remote source which I have no control over. The file is:

    <AssetWarrantyDTO xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Dell.Support.AssetsExternalAPI.Web.Models.V1.Response">
<AdditionalInformation i:nil="true"/>
<AssetWarrantyResponse>
<AssetWarrantyResponse>
<AssetEntitlementData>
<AssetEntitlement>
<EndDate>2010-12-20T23:59:59</EndDate>
<EntitlementType>EXTENDED</EntitlementType>
<ItemNumber>983-4252</ItemNumber>
<ServiceLevelCode>ND</ServiceLevelCode>
<ServiceLevelDescription>Next Business Day Onsite</ServiceLevelDescription>
<ServiceLevelGroup>5</ServiceLevelGroup>
<ServiceProvider>UNY</ServiceProvider>
<StartDate>2008-12-21T00:00:00</StartDate>
</AssetEntitlement>
<AssetEntitlement>
<EndDate>2010-12-20T23:59:59</EndDate>
<EntitlementType>EXTENDED</EntitlementType>
<ItemNumber>987-1139</ItemNumber>
<ServiceLevelCode>TS</ServiceLevelCode>
<ServiceLevelDescription>ProSupport</ServiceLevelDescription>
<ServiceLevelGroup>8</ServiceLevelGroup>
<ServiceProvider>DELL</ServiceProvider>
<StartDate>2008-12-21T00:00:00</StartDate>
</AssetEntitlement>
<AssetEntitlement>
<EndDate>2008-12-20T23:59:59</EndDate>
<EntitlementType>INITIAL</EntitlementType>
<ItemNumber>984-0210</ItemNumber>
<ServiceLevelCode>ND</ServiceLevelCode>
<ServiceLevelDescription>Next Business Day Onsite</ServiceLevelDescription>
<ServiceLevelGroup>5</ServiceLevelGroup>
<ServiceProvider>UNY</ServiceProvider>
<StartDate>2007-12-20T00:00:00</StartDate>
</AssetEntitlement>
<AssetEntitlement>
<EndDate>2008-12-20T23:59:59</EndDate>
<EntitlementType>INITIAL</EntitlementType>
<ItemNumber>987-1308</ItemNumber>
<ServiceLevelCode>TS</ServiceLevelCode>
<ServiceLevelDescription>ProSupport</ServiceLevelDescription>
<ServiceLevelGroup>8</ServiceLevelGroup>
<ServiceProvider>DELL</ServiceProvider>
<StartDate>2007-12-20T00:00:00</StartDate>
</AssetEntitlement>
</AssetEntitlementData>
<AssetHeaderData>
<BUID>11</BUID>
<CountryLookupCode>US</CountryLookupCode>
<CustomerNumber>64724056</CustomerNumber>
<IsDuplicate>false</IsDuplicate>
<ItemClassCode>`U060</ItemClassCode>
<LocalChannel>17</LocalChannel>
<MachineDescription>Precision T3400</MachineDescription>
<OrderNumber>979857987</OrderNumber>
<ParentServiceTag i:nil="true"/>
<ServiceTag>7P3VBU1</ServiceTag>
<ShipDate>2007-12-20T00:00:00</ShipDate>
</AssetHeaderData>
<ProductHeaderData>
<LOB>Dell Precision WorkStation</LOB>
<LOBFriendlyName>Precision WorkStation</LOBFriendlyName>
<ProductFamily>Desktops & All-in-Ones</ProductFamily>
<ProductId>precision-t3400</ProductId>
<SystemDescription>Precision T3400</SystemDescription>
</ProductHeaderData>
</AssetWarrantyResponse>
</AssetWarrantyResponse>
<ExcessTags>
<BadAssets xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</ExcessTags>
<InvalidBILAssets>
<BadAssets xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</InvalidBILAssets>
<InvalidFormatAssets>
<BadAssets xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</InvalidFormatAssets>
</AssetWarrantyDTO>

Here is the Final code not including the setting of the URI variable for the API URL.

protected void Unnamed1_Click(object sender, EventArgs e)
{
    string Serial = TextBox1.Text.ToUpper();
    URI = String.Format(URI, Serial);        
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URI);
    request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3";
    request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
    CookieContainer aCookie = new CookieContainer();
    request.CookieContainer = aCookie;
    WebResponse pageResponse = request.GetResponse();
    Stream responseStream = pageResponse.GetResponseStream();        
    string xml = string.Empty;
    using (StreamReader streamRead = new StreamReader(responseStream))
    {
        xml = streamRead.ReadToEnd();            
    }
    XmlDocument doc1 = new XmlDocument();       
    doc1.LoadXml(xml);
    string _byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
    if (xml.StartsWith(_byteOrderMarkUtf8))
    {
        var lastIndexOfUtf8 = _byteOrderMarkUtf8.Length - 1;
        xml = xml.Remove(0, lastIndexOfUtf8);
        //Label2.Text = "BOM found.";
    }
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc1.NameTable);
    nsmgr.AddNamespace("j", "http://schemas.datacontract.org/2004/07/Dell.Support.AssetsExternalAPI.Web.Models.V1.Response");
    XmlNodeList nodes = doc1.SelectNodes(".//j:AssetWarrantyResponse/j:AssetWarrantyResponse/j:AssetEntitlementData", nsmgr);       
    //Make a list to hold the start dates 
    System.Collections.ArrayList startDates = new System.Collections.ArrayList();
    //Make a list to hold the end dates 
    System.Collections.ArrayList endDates = new System.Collections.ArrayList();
    //Create a regex for finding just the date and discarding the time value which can alter tha date if the time is 24:00 (euro standard)
    Regex r = new Regex(@"\d{4}-\d{1,2}-\d{1,2}", RegexOptions.IgnoreCase);
    //Set the culture to format the date as US region
    CultureInfo dtFormat = new CultureInfo("en-US", false);
    foreach (XmlNode node in nodes)
    {
        foreach (XmlNode childNode in node.ChildNodes)
        {            
        string startDate = childNode["StartDate"].InnerText;

        if (startDate != null)
            {
                MatchCollection mcl1 = r.Matches(startDate);
                startDates.Add(DateTime.Parse(mcl1[0].ToString(), dtFormat));
            }

        string endDate = childNode["EndDate"].InnerText;
        if (endDate != null)
            {

                MatchCollection mcl2 = r.Matches(endDate);
                endDates.Add(DateTime.Parse(mcl2[0].ToString(), dtFormat));
            } 
        }
        startDates.Sort();
        endDates.Sort();
        DateTime wStartDate = new DateTime();
        DateTime wEndDate = new DateTime();
        //if (dates.Count > 1) wStartDate = (DateTime)dates[dates.Count - 1];
        if (startDates.Count >= 1) wStartDate = (DateTime)startDates[0];
        Label1.Text = wStartDate.ToString("MM/dd/yyyy");
        if (endDates.Count >= 1) wEndDate = (DateTime)endDates[endDates.Count - 1];
        Label2.Text = wEndDate.ToString("MM/dd/yyyy");
        //Label2.Text = tempc;
        //Label3.Text = feels;
    }
    nodes = doc1.SelectNodes(".//j:AssetWarrantyResponse/j:AssetWarrantyResponse/j:AssetHeaderData", nsmgr);
    foreach (XmlNode node in nodes)
     {
        try
         { 
            string custNumber = node["CustomerNumber"].InnerText;
            string model = node["MachineDescription"].InnerText;
            string orderNumber = node["OrderNumber"].InnerText;
            string serialNumber = node["ServiceTag"].InnerText;
            Label3.Text = custNumber;
            Label4.Text = model;
            Label5.Text = orderNumber;
            Label6.Text = serialNumber;

         }
        catch (Exception ex)
         {
             dbgLabel.Text = ex.Message;
         }
     }
}
user1431356
  • 854
  • 7
  • 17

1 Answers1

0

You are looking for AssetWarrantyResponse in namespace http://www.w3.org/2001/XMLSchema-instance (the namespace you have bound to prefix "i") but it is actually in namespace http://schemas.datacontract.org/2004/07/Dell.Support.AssetsExternalAPI.Web.Models.V1.Response. Bind a prefix to that namespace (anything will do, e.g "p") and use that prefix in your query, e.g. p:AssetWarrantyResponse, and similarly for other element names.

I wonder if you are spending too much time trying to look for example code that exactly matches what you want to do, and not enough time studying the underlying concepts of the language so that you can apply them to your own problems. Get some good XML books and read them.

There's another problem with your XPath, which is the "/" at the end of the path. That's invalid syntax. If that's the cause of the error then I'm not very impressed with your XPath processor's diagnostics.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • "Expression must evaluate to a node-set" is the error .Net generates for invalid XPath ending with `/` (which is technically correct, but not helpful - http://stackoverflow.com/questions/17839989/expression-must-evaluate-to-a-node-set). – Alexei Levenkov Oct 06 '16 at 21:30
  • Applying suggestions from both responses above leaves me now with this error : Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function. Edited original post to reflect changes. – user1431356 Oct 11 '16 at 14:10
  • I got partially past the Xpath string issue. The xpath is now correct-ish, however, the StartDate element is returning null. Code Edited to reflect current changes. – user1431356 Oct 11 '16 at 14:23
  • I see why it is null. the first and only node in nodes is AssetEntitlementData which should be the parent not the child. What? – user1431356 Oct 11 '16 at 15:21