Home > other >  Extracting mixed-order data of type xml that I get from API
Extracting mixed-order data of type xml that I get from API

Time:09-20

I am getting data with the help of api for credit card information. The data I got is as follows.

<<?xml version="1.0" encoding="ISO-8859-9"?>
<CC5Response>
  <ProcReturnCode>00</ProcReturnCode>
  <Response>Approved</Response>
  <Extra>
    <PAN1LABEL>PRICE</PAN1LABEL>
    <PAN2INDEXORDER>1</PAN2INDEXORDER>
    <PAN2STATUS>NO</PAN2STATUS>
    <SAFEKEYLASTMODIFIED>11/22/333</SAFEKEYLASTMODIFIED>
    <PAN2INDEXACCOUNTCLOSURE>00</PAN2INDEXACCOUNTCLOSURE>
    <PAN1STATUS>NO</PAN1STATUS>
    <PAN1INDEXACCOUNTCLOSURE>00</PAN1INDEXACCOUNTCLOSURE>
    <PAN2EXPIRY>00.1111</PAN2EXPIRY>
    <PAN1OWNER>JOHN DAVIS</PAN1OWNER>
    <PAN2LABEL>PRODUCT BUY</PAN2LABEL>
    <PAN2DESCRIPTION>DESCRIPION</PAN2DESCRIPTION>
    <PAN1>1111 22** **** 3333</PAN1>
   <PAN2>1111 22** **** 3333</PAN2>
    <PAN2OWNER>JOHN DAVIS</PAN2OWNER>
    <PAN1EXPIRY>02.2025</PAN1EXPIRY>
    <NUMBEROFPANS>3</NUMBEROFPANS>
    <PAN1INDEXORDER>1</PAN1INDEXORDER>
    <PAN1DESCRIPTION>PRODUCT NO</PAN1DESCRIPTION>
  </Extra>
</CC5Response>

I need to get the data with the whole word "PAN" in it. I'll add this to the user's saved card info screen. I tried a few times but it didn't work. Here are the codes i tried

List<string> list = new List<string>();
list.add(responseFromServer); //"responseFromServer" data from api
string[] getPanArray = list.ToArray();
List<string> panlist = new List<string>();
string pan = "PAN";
foreach (var item in getPanArray)
{
    if (item.Contains(pan))
    {
       panlist.Add(item);
    }
 }

Latter

List<string> list = new List<string>();
list.Add(responseFromServer);
String[] test = list.ToArray();
String text = "PAN";
String[] result = test.Where(s =>
     {
       Boolean isInThere = true;
       Char[] textArray = text.ToCharArray();
        foreach (Char c in textArray)
        {
           if (!s.Contains(c))
                    isInThere = false;
         }
           return isInThere;
       }).ToArray();

CodePudding user response:

So, since responseFromServer is a string, first, parse the string into an XDocument.

using System.Xml.Linq;

...

var response = XDocument.Parse(responseFromServer);

Then you can use LINQ to filter out the elements you are interested in.

using System.Linq;

...

var justPans = response
                 .Element("CC5Response")
                 .Element("Extra")
                 .Elements().Where(e => e.Name.LocalName.Contains("PAN"));

Gives you an IEnumerable of XElement for just the PAN elements. Then you can extract the contexts of valid text elements.

var panContents = justPans
                      .Select(e => e.FirstNode)
                      .OfType<XText>()
                      .Select(t => t.Value)
                      .ToList();

This is demoed here.

CodePudding user response:

That is a horribly formatted XML, and its contents do not make any sense. For example, it says it has 3 PANs:

    <NUMBEROFPANS>3</NUMBEROFPANS>

But I only see two.

Furthermore, what is the purpose of having variable starting index and then have it the same for two entries?

    <PAN1INDEXORDER>1</PAN1INDEXORDER>

In short, this is next to impossible to parse easily using direct deserialization into classes which is how you are supposed to parse XML in C#.

The data from the API should be reformatted by the host to look like this before they send it to you:

<Extra>
    <Items>
        <Item>
            <INDEXORDER>1</INDEXORDER>
            <LABEL>PRICE</LABEL>
            <STATUS>NO</STATUS>
            <INDEXACCOUNTCLOSURE>00</INDEXACCOUNTCLOSURE>
            <OWNER>JOHN DAVIS</OWNER>
            <PAN>1111 22** **** 3333</PAN>
            <EXPIRY>02.2025</EXPIRY>
            <DESCRIPTION>PRODUCT NO</DESCRIPTION>
        </Item>
        <Item>
            <INDEXORDER>1</INDEXORDER>
            <LABEL>PRODUCT BUY</LABEL>
            <STATUS>NO</STATUS>
            <INDEXACCOUNTCLOSURE>00</INDEXACCOUNTCLOSURE>
            <OWNER>JOHN DAVIS</OWNER>
            <PAN>1111 22** **** 3333</PAN>
            <EXPIRY>00.1111</EXPIRY>
            <DESCRIPTION>DESCRIPION</DESCRIPTION>
        </Item>
    </Items>
    <SAFEKEYLASTMODIFIED>11/22/333</SAFEKEYLASTMODIFIED>
</Extra>

In order for it to be easily parsed. Then it is a simple matter of making model classes:

public class Item
{
    public int      IndexOrder;
    public string   Label;
    public string   Status;
    public int      IndexAccountClosure;
    public string   Owner;
    public string   PAN;
    public string   Expiry;
    public string   Description;
}

public class ExtraData
{
    public Item[]   Items;
    public string   SafeKeyLastModified;
}

public class CCSResponse
{
    public  int         ProcReturnCode;
    public  string      Response;
    public  ExtraData   Extra;
}

And then letting XMLSerializer do its job:

    string XMLTextFromAPI = YourAPICallHere();
    CCSResponse data;
    XmlSerializer serializer = new XmlSerializer(typeof(CCSResponse));
    using (TextReader reader = new StringReader(XMLTextFromAPI)) {
        data = (CCSResponse)serializer.Deserialize(reader);
    }

Afterwards you can just access the data like this:

    foreach (Item i in data.Extra.Items) {
        // do whatever you need with those PANs
    }

Anything other than that, and you are asking for trouble both in writing and in maintaining that code later.

TL;DR — sometimes a proper solution is not to accept to work with garbage data that you are given and ask them to change it, at least that's what I would do if I were in your place.

I am sure someone else will post an actual answer on how to parse that garbage data which will probably involve regex or LINQ in some way.

  • Related