Link to home
Start Free TrialLog in
Avatar of shankarraj
shankarraj

asked on

sending integer array of data

Hi,

I am generating some numbers in my server program. I would like to send this integer array to the client in the form of message.
I will retrieve the sent numbers using the header in client.

The generated numbers is in the form of integer array as:
int MyNumbers[10];
These numbers are put into message as:
char charArrData[100];
sprintf(charArrData, "<Message><MyNumbers><header>NumberSeries</header><data>
%d</data></MyNumbers></Message>", Numbers);
Here , I am facing the problem in forming the message using the inetger array by using sprintf().
Please help me like how to form the message using the sprintf( ) here and getting the value using the header at the client side.

Thanks,
shankarraj
Avatar of Jaime Olivares
Jaime Olivares
Flag of Peru image

to fill you message you will need a loop, use another little buffer:

char OneNumber[10]; /* add this */
int MyNumbers[10];
char charArrData[100];  /* I suggest you to use 200 */
int i;

strcpy(charArrData, "<Message><MyNumbers><header>NumberSeries</header><data>");
for (i=0; i<10; i++)
{
      sprintf(OneNumber, "%s%d", i>0?",":"", MyNumbers[i]);   /* add a comma, excepting 1st value */
      strcat(charArrData, OneNumber);
}
strcat(charArrData, "</data></MyNumbers></Message>");
Avatar of shankarraj
shankarraj

ASKER

Hi,

Let us assume that I have sent following mesage from my server program and the message is received at my client program as:
<Message><MyNumbers><header>NumberSeries</header><data>20,41,57</data></MyNumbers></Message>

Also, I would like my API as:
HubMessage *ptrMessage;
int Numbers[3]=ptrHubMessage->getFieldValue("NumberSeries", 1);
Please tell me like how to I retrieve the array of integers from the message in the above case as the array of numbers are separated by a comma in the mesage?

Thanks,
shankarraj



Do you need a pure C solution?
A C++ solution will be cleaner and easier.
Hi,

I am looking for C++ solution.
I would like to retrieve all the array values at a stretch from the message in the client side as I mentioned earlier. i.e. int Numbers[3]=ptrHubMessage->getFieldValue("NumberSeries", 1);

Please help me to do this.

Thanks,
shankarraj
>> int Numbers[3]=ptrHubMessage->getFieldValue("NumberSeries", 1);
How you will know that there are 3 elements before parsing the values?
A pure C solution will require a malloc() or calloc() allocation;
A C++ solution will require to create the array with a new operator.

so, it could be something like:
int *Numbers = ptrHubMessage->getFieldValue("NumberSeries", 1);
don't know what 1 means.

But Numbers will not tell you the array size. A more C++ like solution will be:

std::vector<int> *Numbers = ptrHubMessage->getFieldValue("NumberSeries", 1);

To acomplish this, you will have to parse the message itself, and extract the numbers array as a string. a STL std::string will be easier to process.
Then you have to split the string into values.  Something like this:

vector<int>* ParseValues(const string& str)
{
    vector<int>* tokens = new vector<int>();

    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(",", 0);
    // Find first "non-delimiter".
    string::size_type pos  = str.find_first_of(",", lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(atoi(str.substr(lastPos, pos - lastPos).c_str()));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(",", pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(",", lastPos);
    }
}
Hi,
 int Numbers[3]=ptrHubMessage->getFieldValue("NumberSeries", 1);
where 1 is the row number.
Also, as you have told, I will not be knowing that there are 3 elements before parsing the values. There may be any number of elements in the array.

Thanks,
shankarraj

Being 1 the row number, you have to scan all the file until you reach the desired row.
but in an XML document, a row is an ambigous term, maybe a record, or Message number would be more exact, because a Message can occupy more than 1 text rows, or maybe 2 messages can occupy 1 single text rows.

Sounds like you will require some xml parser ...
>>>> int Numbers[3]=ptrHubMessage->getFieldValue("NumberSeries", 1);
That cannot work for different reasons:

1. A fixed array variable like 'int Numbers[3]' only can be initialized by a const array:

   int Numbers[3] = { 1, 2, 3};

but not by a function return value.

2. The function at the right side of an assignment doesn't know the size of the array to return. If it is dynamic we need a dynamic array at the left side of the assignment as well.

You can heal both by something like

   int Numbers[3];
   if (ptrHubMessage->getFieldValue(Numbers, 3, "NumberSeries", 1))
   {
         // ok we got 3 values from serialized message
   }

where the getFieldValue has overloads for different result types.

Regards, Alex



Hi jaime_olivares:,

Please tell me like how to read the integer  array values from the vector: tokens in the following program which is given by you in your earlier answer:

std::vector<int> *Numbers = ptrHubMessage->getFieldValue("NumberSeries", 1);

To acomplish this, you will have to parse the message itself, and extract the numbers array as a string. a STL std::string will be easier to process.
Then you have to split the string into values.  Something like this:

vector<int>* ParseValues(const string& str)
{
    vector<int>* tokens = new vector<int>();

    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(",", 0);
    // Find first "non-delimiter".
    string::size_type pos  = str.find_first_of(",", lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(atoi(str.substr(lastPos, pos - lastPos).c_str()));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(",", pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(",", lastPos);
    }
}

Please help me here to read the integer array values from the vector tokens .

Thanks,
shankarraj
vector<> is similar to an array. Easiest way to access is with direct indexing, like:

int a;
for (int i=0; i<theVector.size(); i++)
{
     a= theVector[i];
     // do something with a
}
Also, assumming you will hold the vector object with a pointer, it shoul be:

int a;
for (int i=0; i<pVector->size(); i++)
{
     a= (*pVector)[i];
     // do something with a
}

finally you have to discard the vector object when you no longer need it, to avoid a memory leak:

delete pVector;
Hi jaime_olivares,

<Message><MyNumbers><header>NumberSeries</header><data>9,5,26,30,43,39,31,30,40,10,32</data></MyNumbers></Message>
For the above message, when I used following vector program:
I am getting the output value as: 0 5 26 30 43 39 31 30 40 10 32

Note: I am using cout<<atoi(str.substr(lastPos, pos - lastPos).c_str()); in your program to display the values.  

I am observing value: 0 instead of 9. Please tell me the problem for receiving value 0 instead of 9 here.

vector<int>* ParseValues(const string& str)
{
    vector<int>* tokens = new vector<int>();

    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(",", 0);
    // Find first "non-delimiter".
    string::size_type pos  = str.find_first_of(",", lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(atoi(str.substr(lastPos, pos - lastPos).c_str()));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(",", pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(",", lastPos);
    }
}



you cannot pass all the string to the ParseValues function, you have to separate first to have just:
9,5,26,30,43,39,31,30,40,10,32
Hi jaime olivares,

I need to retrieve all the values from the message:
<Message><MyNumbers><header>NumberSeries</header><data>9,5,26,30,43,39,31,30,40,10,32</data></MyNumbers></Message>
Please help me to do this using your vector program.

Thanks,
shankarraj
could be something like this:
std::string full = "<Message><MyNumbers><header>NumberSeries</header><data>9,5,26,30,43,39,31,30,40,10,32</data></MyNumbers></Message>"

int start = full.find("<data>",0);
int end = full.find("</data",0);
if (start!=std::string::npos && end!=std::string::npos)
{
      std:string portion = full.substr(start+6, start-end-6);
      vector<int> *list = ParseValues(portion);
}


Better use:

int ParseValues(const string& s, vector<int>& tokens)
{
    string str = s;  // take a writeable copy
    s += ',';    // add a delimiter at end

    string::size_type lastPos = 0;
    string::size_type pos  = 0;

    while ((pos = str.find(',', lastPos)) != string::npos)
    {
        // Found a token, add it to the vector.
        if (pos > lastPos)
        {
             int i;
             istringstream iss(str.substr(lastPos, pos - lastPos));
             if (iss >> i)
             {
                   tokens.push_back(i);
             }
             lastPos = pos+1;
         }
    }
     return tokens.size();
}

Regards, Alex
correction:

int ParseValues(const string& s, vector<int>& tokens)
{
    string str = s;  // take a writeable copy
    s += ',';    // add a delimiter at end

    string::size_type lastPos = 0;
    string::size_type pos  = 0;

    while ((pos = str.find(',', lastPos)) != string::npos)
    {
        // Found a token, add it to the vector.
        if (pos > lastPos)
        {
             int i;
             istringstream iss(str.substr(lastPos, pos - lastPos));
             if (iss >> i)
             {
                   tokens.push_back(i);
             }
         }
         lastPos = pos+1;   // must be done in every case
    }
     return tokens.size();
}

ASKER CERTIFIED SOLUTION
Avatar of Jaime Olivares
Jaime Olivares
Flag of Peru image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>>>> the problem is that the author is sending the full xml string to the Parse function
The above parser should work beside of the very first number cause it only extracts numbers separated by comma. To make it valid when passing all xml string it is:

int ParseValues(const string& s, vector<int>& tokens)
{
    string::size_type pos  = s.find("<data>");
    string::size_type lastPos = s.find("</data>");
    if (pos == string::npos || lastPos == string::npos || lastPos < pos)
          return -1;  // invalid xml  

    pos += sizeof("<data>")-1;
    string str = s.substr(pos, lastPos - pos);  // take data portion
    str += ',';    // add a delimiter at end

    while ((pos = str.find(',', lastPos)) != string::npos)
    {
        // Found a token, add it to the vector.
        if (pos > lastPos)
        {
             int i;
             istringstream iss(str.substr(lastPos, pos - lastPos));
             if (iss >> i)
             {
                   tokens.push_back(i);
             }
         }
         lastPos = pos+1;   // must be done in every case
    }
     return tokens.size();
}

That should do it.

Correction:

    lastPos = 0;  // reset lastPos before while loop
my ParseValues proposal is just to parse a clean list, not the entire XML, I think mixing both tasks does not contribute to legibility.
That's why I have put in a separted post.
>>>> I think mixing both tasks does not contribute to legibility.
You are right. But if the xml is only 'boxing' and is not intended to provide a full independent and enhanceable xml document, parsing it that way maybe is a pragmatical approach. I am pretty sure that there are much more self-written parsers like the one I posted than full xml parsers. But the asker has to decide.