• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 238
  • Last Modified:

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
0
shankarraj
Asked:
shankarraj
  • 10
  • 6
  • 6
1 Solution
 
Jaime OlivaresSoftware ArchitectCommented:
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>");
0
 
shankarrajAuthor Commented:
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



0
 
Jaime OlivaresSoftware ArchitectCommented:
Do you need a pure C solution?
A C++ solution will be cleaner and easier.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
shankarrajAuthor Commented:
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
0
 
Jaime OlivaresSoftware ArchitectCommented:
>> 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);
    }
}
0
 
shankarrajAuthor Commented:
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

0
 
Jaime OlivaresSoftware ArchitectCommented:
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 ...
0
 
itsmeandnobodyelseCommented:
>>>> 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



0
 
shankarrajAuthor Commented:
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
0
 
Jaime OlivaresSoftware ArchitectCommented:
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
}
0
 
Jaime OlivaresSoftware ArchitectCommented:
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;
0
 
shankarrajAuthor Commented:
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);
    }
}



0
 
Jaime OlivaresSoftware ArchitectCommented:
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
0
 
shankarrajAuthor Commented:
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
0
 
Jaime OlivaresSoftware ArchitectCommented:
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);
}


0
 
itsmeandnobodyelseCommented:
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
0
 
itsmeandnobodyelseCommented:
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();
}

0
 
Jaime OlivaresSoftware ArchitectCommented:
Alex,
the problem is that the author is sending the full xml string to the Parse function, without extracting the data portion.
0
 
itsmeandnobodyelseCommented:
>>>> 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.

0
 
itsmeandnobodyelseCommented:
Correction:

    lastPos = 0;  // reset lastPos before while loop
0
 
Jaime OlivaresSoftware ArchitectCommented:
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.
0
 
itsmeandnobodyelseCommented:
>>>> 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.
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 10
  • 6
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now