Parse XML to Variables for use throughout sketch

Noob here and I'm trying to have the Arduino parse an XML file and save the results to variables that I can later pass onto an LCD screen as well as to pumps for use. My project is a "mixing machine" for virgin drinks. I've tried several different XML Parsers however I can't seem to get the results to be stored as strings or character arrays so that I can use them elsewhere in the program. I just can't seem to get the darn thing working. I can get the variables saved in the function and used there, however anytime I try and display them on the Serial in the main loop I get nothing. :frowning:

Here is the contents of my XML file:

<instructions>
<name>Kirk Holmes</name>
<flavor_name>Root Beer Float</flavor_name>
<mix_volume>15</mix_volume>
<pump_instructions>
<pump1>1</pump1>
<pump2>2</pump2>
<pump3>3</pump3>
<pump4>4</pump4>
<pump5>5</pump5>
</pump_instructions>
<date_time_submitted>
<month>6</month>
<day>20</day>
<year>2013</year>
<hour>12</hour>
<minute>01</minute>
<second>00</second>
</date_time_submitted>
</instructions>

Here is my code:

//////////////////////////////////////////////
// Get XML formatted data from the web.
// 1/6/08 Bob S. - Created
//
//  Assumptions: single XML line looks like: 
//    <tag>data</tag> or <tag>data 
//
// Get current weather observation for Raleigh from weather.gov in XML format
//
//////////////////////////////////////////////

// Include description files for other libraries used (if any)
#include <string.h>
#include <Ethernet.h>
#include <SPI.h>;
// Define Constants
// Max string length may have to be adjusted depending on data to be extracted
#define MAX_STRING_LEN  20

// Setup vars
char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {'<', '/', '\0'};
int len;

// DECLARED VARIABLES HERE FOR GLOBAL USE
char* name;
char* flavor_name;
char* mix_volume;

// Flags to differentiate XML tags from document elements (ie. data)
boolean tagFlag = false;
boolean dataFlag = false;

// Ethernet vars
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 177 };
byte server[] = { 192, 168, 1, 110 }; // My server at home

// Start ethernet client
EthernetClient client;

void setup()
{
  Serial.begin(9600);
  Serial.println("Starting WebWx");
  Serial.println("connecting...");
  Ethernet.begin(mac, ip);
  delay(1000);

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET /instructions.xml HTTP/1.0");    
    client.println();
    delay(2000);
  } else {
    Serial.println("connection failed");
  }  
}

void loop() {

  // Read serial data in from web:
  while (client.available()) {
    serialEvent(); 
  }

  if (!client.connected()) {
    //Serial.println();
    //Serial.println("Disconnected");
    client.stop();

    // Time until next update
    //Serial.println("Waiting");
    for (int t = 1; t <= 15; t++) {
      delay(60000); // 1 minute
    }

    if (client.connect(server, 80)) {
      //Serial.println("Reconnected");
      client.println("GET /instructions.xml HTTP/1.0");    
      client.println();
      delay(2000);
    } else {
      Serial.println("Reconnect failed");
    }       
  }
}

// Process each char from web
void serialEvent() {

   // Read a char
      char inChar = client.read();
   //Serial.print(".");
  
   if (inChar == '<') {
      addChar(inChar, tmpStr);
      tagFlag = true;
      dataFlag = false;

   } else if (inChar == '>') {
      addChar(inChar, tmpStr);

      if (tagFlag) {      
         strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
      }

      // Clear tmp
      clearStr(tmpStr);

      tagFlag = false;
      dataFlag = true;      
      
   } else if (inChar != 10) {
      if (tagFlag) {
         // Add tag char to string
         addChar(inChar, tmpStr);

         // Check for </XML> end tag, ignore it
         if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
            clearStr(tmpStr);
            tagFlag = false;
            dataFlag = false;
         }
      }
      
      if (dataFlag) {
         // Add data char to string
         addChar(inChar, dataStr);
      }
   }  
  
   // If a LF, process the line
   if (inChar == 10 ) {

/*
      Serial.print("tagStr: ");
      Serial.println(tagStr);
      Serial.print("dataStr: ");
      Serial.println(dataStr);
*/

      // Find specific tags and print data
      if (matchTag("<name>")) {
         Serial.println("Name: ");
         name = dataStr;
         Serial.print(name);
      }
      if (matchTag("<flavor_name>")) {
         Serial.print("   Flavor Name: ");
         flavor_name = dataStr;
         Serial.print(flavor_name);
      }
      if (matchTag("<mix_volume>")) {
         Serial.print("   Volume to Mix: ");
         mix_volume = dataStr;
         Serial.print(mix_volume);
         Serial.print("   ");
      }

      // Clear all strings
      clearStr(tmpStr);
      clearStr(tagStr);
      clearStr(dataStr);

      // Clear Flags
      tagFlag = false;
      dataFlag = false;
   }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
   int len = strlen(str);
   for (int c = 0; c < len; c++) {
      str[c] = 0;
   }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
   char *tagMsg  = "<TRUNCATED_TAG>";
   char *dataMsg = "-TRUNCATED_DATA-";

   // Check the max size of the string to make sure it doesn't grow too
   // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
   // and replace it with a warning message.
   if (strlen(str) > MAX_STRING_LEN - 2) {
      if (tagFlag) {
         clearStr(tagStr);
         strcpy(tagStr,tagMsg);
      }
      if (dataFlag) {
         clearStr(dataStr);
         strcpy(dataStr,dataMsg);
      }

      // Clear the temp buffer and flags to stop current processing 
      clearStr(tmpStr);
      tagFlag = false;
      dataFlag = false;

   } else {
      // Add char to string
      str[strlen(str)] = ch;
   }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
   if ( strcmp(tagStr, searchTag) == 0 ) {
      return true;
   } else {
      return false;
   }
}
  while (client.available()) {
    serialEvent(); 
  }

Getting data from the client is NOT a serial event. Use a meaningful name for the function, like gZG78.

What does your serial output look like?

Pointing name to an array, NULLing the array, and then printing name will get you nowhere. You are pointing to the memory that you just NULLed.

I agree the function name is incorrect. Right now I just took the code I found online and have adjusted the areas that I need to adjust until I can get it working correctly.

As it stands right now I get the following Serial Display:

Starting WebWx
connecting...
connected
Name: 
Kirk Holmes
   Flavor Name: Root Beer Float
   Volume to Mix: 15

Although the formatting is off this does display the variables I want, however when I adjust the code to display the information elsewhere I get nothing, even though I declared the variables in the beginning of the sketch. When I comment out the Serial Display lines in serialEvent, add a client.stop() after the if statements, and change:

  while (client.available()) {
    serialEvent(); 
  }

to

  while (client.available()) {
    serialEvent(); 
  }
Serial.println("Name: ");
Serial.print(name);
Serial.print("   Flavor Name: ");
Serial.print(flavor_name);
Serial.print("   Volume to Mix: ");
Serial.print(mix_volume);
Serial.print("   ");

my serial display becomes:

Starting WebWx
connecting...
connected
Name: 
   Flavor Name:    Volume to Mix:

I'm still pretty new to the Arduno/C language. I'm used to PHP and BASIC so I don't 100% understand the whole array/string concept you're discussing in the end of your post. Any help would be greatly appreciated because I've read and reread the reference pages on Strings and Arrays and I'm still lost (been taking quite a hit to my pride/ego LOL)

Kirk

Although the formatting is off this does display the variables I want, however when I adjust the code to display the information elsewhere I get nothing, even though I declared the variables in the beginning of the sketch.

So, one sketch, not shown, produces some data. Another sketch, that may or may not be the one shown, does not.

Move your crystal ball put of the way, so we can see your code!

Crystal Ball has been moved....it's basically the same exact code except I'm displaying the variables set in the function in the main loop and I get nothing :frowning: I'm sure it is something quite simple with setting the incoming string with the data I want to store as a variable that can then be used anywhere in the sketch. I'm just new to the whole array/string aspect of this type of coding....still used to BASIC and PHP coding :frowning:

//////////////////////////////////////////////
// Get XML formatted data from the web.
// 1/6/08 Bob S. - Created
//
//  Assumptions: single XML line looks like: 
//    <tag>data</tag> or <tag>data 
//
// Get current weather observation for Raleigh from weather.gov in XML format
//
//////////////////////////////////////////////

// Include description files for other libraries used (if any)
#include <string.h>
#include <Ethernet.h>
#include <SPI.h>;
// Define Constants
// Max string length may have to be adjusted depending on data to be extracted
#define MAX_STRING_LEN  20

// Setup vars
char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {'<', '/', '\0'};
int len;

// DECLARED VARIABLES HERE FOR GLOBAL USE
char* name;
char* flavor_name;
char* mix_volume;

// Flags to differentiate XML tags from document elements (ie. data)
boolean tagFlag = false;
boolean dataFlag = false;

// Ethernet vars
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 177 };
byte server[] = { 192, 168, 1, 110 }; // My server at home

// Start ethernet client
EthernetClient client;

void setup()
{
  Serial.begin(9600);
  Serial.println("Starting WebWx");
  Serial.println("connecting...");
  Ethernet.begin(mac, ip);
  delay(1000);

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET /instructions.xml HTTP/1.0");    
    client.println();
    delay(2000);
  } else {
    Serial.println("connection failed");
  }  
}

void loop() {

  // Read serial data in from web:
  while (client.available()) {
    serialEvent(); 
  }
Serial.println("Name: ");
Serial.print(name);
Serial.print("   Flavor Name: ");
Serial.print(flavor_name);
Serial.print("   Volume to Mix: ");
Serial.print(mix_volume);
Serial.print("   ");

  if (!client.connected()) {
    //Serial.println();
    //Serial.println("Disconnected");
    client.stop();

    // Time until next update
    //Serial.println("Waiting");
    for (int t = 1; t <= 15; t++) {
      delay(60000); // 1 minute
    }

    if (client.connect(server, 80)) {
      //Serial.println("Reconnected");
      client.println("GET /instructions.xml HTTP/1.0");    
      client.println();
      delay(2000);
    } else {
      Serial.println("Reconnect failed");
    }       
  }
}

// Process each char from web
void serialEvent() {

   // Read a char
      char inChar = client.read();
   //Serial.print(".");
  
   if (inChar == '<') {
      addChar(inChar, tmpStr);
      tagFlag = true;
      dataFlag = false;

   } else if (inChar == '>') {
      addChar(inChar, tmpStr);

      if (tagFlag) {      
         strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
      }

      // Clear tmp
      clearStr(tmpStr);

      tagFlag = false;
      dataFlag = true;      
      
   } else if (inChar != 10) {
      if (tagFlag) {
         // Add tag char to string
         addChar(inChar, tmpStr);

         // Check for </XML> end tag, ignore it
         if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
            clearStr(tmpStr);
            tagFlag = false;
            dataFlag = false;
         }
      }
      
      if (dataFlag) {
         // Add data char to string
         addChar(inChar, dataStr);
      }
   }  
  
   // If a LF, process the line
   if (inChar == 10 ) {

/*
      Serial.print("tagStr: ");
      Serial.println(tagStr);
      Serial.print("dataStr: ");
      Serial.println(dataStr);
*/

      // Find specific tags and print data
      if (matchTag("<name>")) {
         //Serial.println("Name: ");
         name = dataStr;
         //Serial.print(name);
      }
      if (matchTag("<flavor_name>")) {
         //Serial.print("   Flavor Name: ");
         flavor_name = dataStr;
         //Serial.print(flavor_name);
      }
      if (matchTag("<mix_volume>")) {
         //Serial.print("   Volume to Mix: ");
         mix_volume = dataStr;
         //Serial.print(mix_volume);
         //Serial.print("   ");
      }

      // Clear all strings
      clearStr(tmpStr);
      clearStr(tagStr);
      clearStr(dataStr);

      // Clear Flags
      tagFlag = false;
      dataFlag = false;
   }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
   int len = strlen(str);
   for (int c = 0; c < len; c++) {
      str[c] = 0;
   }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
   char *tagMsg  = "<TRUNCATED_TAG>";
   char *dataMsg = "-TRUNCATED_DATA-";

   // Check the max size of the string to make sure it doesn't grow too
   // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
   // and replace it with a warning message.
   if (strlen(str) > MAX_STRING_LEN - 2) {
      if (tagFlag) {
         clearStr(tagStr);
         strcpy(tagStr,tagMsg);
      }
      if (dataFlag) {
         clearStr(dataStr);
         strcpy(dataStr,dataMsg);
      }

      // Clear the temp buffer and flags to stop current processing 
      clearStr(tmpStr);
      tagFlag = false;
      dataFlag = false;

   } else {
      // Add char to string
      str[strlen(str)] = ch;
   }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
   if ( strcmp(tagStr, searchTag) == 0 ) {
      return true;
   } else {
      return false;
   }
}

Lets look at what is happening. Some client data comes in, so serialEvent is called. In serialEvent, you collect the data into tmpStr or dataStr. When an end marker arrives, the data in tmpStr is copied into tagStr. When a line feed arrives, the data in tmpStr is copied into dataStr.

Depending on what is in tagStr, you point name, flavor_name, or mix_volume to dataStr.

Note that this does NOT copy data to name, flavor_name, or mix_volume. All it does is make name, flavor_name, or mix_volume point to the same memory location as dataStr.

Next, you NULL out dataStr. So, name, flavor_name, or mix_volume now point to an empty string.

You need to make name, flavor_name, and mix_volume be real arrays, and use strcpy() to copy the data there from dataStr, OR, you need to use strdup() to copy the data in dataStr to another location, and point name, flavor_name, or mix_volume to the copy.

That way, when you NULL dataStr, you won't be affecting name, flavor_name, or mix_volume. Be aware, though, that dynamic memory allocation (which is what strdup() does) is not a particularly good idea on an Arduino with so little memory.

Ok I think I'm starting to understand....I made the changes to the code so i'm now using strcpy...but now I'm getting some really weird stuff on serial. I think I can see that it's actually storing the data but it's garbled between a bunch of other ASCII characters. It's also interesting that the serial says that the connection failed and yet it hasn't. I'm so confused!

Here is the modified code (I also added one section to print a bunch of blank lines to clear the serial)

//////////////////////////////////////////////
// Get XML formatted data from the web.
// 1/6/08 Bob S. - Created
//
//  Assumptions: single XML line looks like: 
//    <tag>data</tag> or <tag>data 
//
// Get current weather observation for Raleigh from weather.gov in XML format
//
//////////////////////////////////////////////

// Include description files for other libraries used (if any)
#include <string.h>
#include <Ethernet.h>
#include <SPI.h>;
// Define Constants
// Max string length may have to be adjusted depending on data to be extracted
#define MAX_STRING_LEN  20

// Setup vars
char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {'<', '/', '\0'};
int len;

// DECLARED VARIABLES HERE FOR GLOBAL USE
char* name;
char* flavor_name;
char* mix_volume;

// Flags to differentiate XML tags from document elements (ie. data)
boolean tagFlag = false;
boolean dataFlag = false;

// Ethernet vars
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 177 };
byte server[] = { 192, 168, 1, 110 }; // My server at home

// Start ethernet client
EthernetClient client;

void setup()
{
  Serial.begin(9600);
int var=0;
  while(var < 60){
    //Serial.print(var);
    Serial.println("");
    var++;
  }
  Serial.println("Starting WebWx");
  Serial.println("connecting...");
  Ethernet.begin(mac, ip);
  delay(1000);

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET /instructions.xml HTTP/1.0");    
    client.println();
    delay(2000);
  } else {
    Serial.println("connection failed");
  }  
}

void loop() {
  int var = 0;
  while(var < 60){
    Serial.print("\r");
    var++;
  }
  // Read serial data in from web:
  while (client.available()) {
    serialEvent(); 
  }
Serial.println("Name: ");
Serial.print(name);
Serial.println("Flavor Name: ");
Serial.print(flavor_name);
Serial.println("Volume to Mix: ");
Serial.print(mix_volume);
Serial.print("   ");

  if (!client.connected()) {
    //Serial.println();
    //Serial.println("Disconnected");
    client.stop();

    // Time until next update
    //Serial.println("Waiting");
    for (int t = 1; t <= 15; t++) {
      delay(60000); // 1 minute
    }

    if (client.connect(server, 80)) {
      //Serial.println("Reconnected");
      client.println("GET /instructions.xml HTTP/1.0");    
      client.println();
      delay(2000);
    } else {
      Serial.println("Reconnect failed");
    }       
  }
}

// Process each char from web
void serialEvent() {

   // Read a char
      char inChar = client.read();
   //Serial.print(".");
  
   if (inChar == '<') {
      addChar(inChar, tmpStr);
      tagFlag = true;
      dataFlag = false;

   } else if (inChar == '>') {
      addChar(inChar, tmpStr);

      if (tagFlag) {      
         strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
      }

      // Clear tmp
      clearStr(tmpStr);

      tagFlag = false;
      dataFlag = true;      
      
   } else if (inChar != 10) {
      if (tagFlag) {
         // Add tag char to string
         addChar(inChar, tmpStr);

         // Check for </XML> end tag, ignore it
         if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
            clearStr(tmpStr);
            tagFlag = false;
            dataFlag = false;
         }
      }
      
      if (dataFlag) {
         // Add data char to string
         addChar(inChar, dataStr);
      }
   }  
  
   // If a LF, process the line
   if (inChar == 10 ) {

/*
      Serial.print("tagStr: ");
      Serial.println(tagStr);
      Serial.print("dataStr: ");
      Serial.println(dataStr);
*/

      // Find specific tags and print data
      if (matchTag("<name>")) {
         //Serial.println("Name: ");
         strcpy(name,dataStr);
         //Serial.print(name);
      }
      if (matchTag("<flavor_name>")) {
         //Serial.print("   Flavor Name: ");
         strcpy(flavor_name,dataStr);
         //Serial.print(flavor_name);
      }
      if (matchTag("<mix_volume>")) {
         //Serial.print("   Volume to Mix: ");
         strcpy(mix_volume,dataStr);
         //Serial.print(mix_volume);
         //Serial.print("   ");
      }

      // Clear all strings
      clearStr(tmpStr);
      clearStr(tagStr);
      clearStr(dataStr);

      // Clear Flags
      tagFlag = false;
      dataFlag = false;
   }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
   int len = strlen(str);
   for (int c = 0; c < len; c++) {
      str[c] = 0;
   }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
   char *tagMsg  = "<TRUNCATED_TAG>";
   char *dataMsg = "-TRUNCATED_DATA-";

   // Check the max size of the string to make sure it doesn't grow too
   // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
   // and replace it with a warning message.
   if (strlen(str) > MAX_STRING_LEN - 2) {
      if (tagFlag) {
         clearStr(tagStr);
         strcpy(tagStr,tagMsg);
      }
      if (dataFlag) {
         clearStr(dataStr);
         strcpy(dataStr,dataMsg);
      }

      // Clear the temp buffer and flags to stop current processing 
      clearStr(tmpStr);
      tagFlag = false;
      dataFlag = false;

   } else {
      // Add char to string
      str[strlen(str)] = ch;
   }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
   if ( strcmp(tagStr, searchTag) == 0 ) {
      return true;
   } else {
      return false;
   }
}

Also attached is a screenshot of the serial display since for some reason I can't copy and paste the ASCII characters from serial to the clipboard here in Windows 7.

(It's quite humbling going through this when for the most part I know my way around web dev and a computer so well....reminds me of the days when I started programming in BASIC and then again in PHP. LOL)

I don't see anywhere in your addChar() function where you explicitly null-terminate the string.

YA!!!! BOY THAT TOOK FOREVER!!! BUT a very valuable lesson learned!!! Here is the working code (with a bunch of comments and a modified DHCP Connection portion added to the setup)

I ended up having to manually set the array length at the start of the sketch as well as null each global variable instead of using char*. Now I assume it would be best to manually set the array length if at all possible.

Now any suggestions on how to do this without having to manually set the array length?

Here is the partially finished (albeit hacked to S---) code:

//////////////////////////////////////////////
// Get XML formatted data from the web.
// 1/6/08 Bob S. - Created
//
//  Assumptions: single XML line looks like: 
//    <tag>data</tag> or <tag>data 
//
// Get current weather observation for Raleigh from weather.gov in XML format
//
//////////////////////////////////////////////

// Include description files for other libraries used (if any)
#include <string.h>
#include <Ethernet.h>
#include <SPI.h>;
// Define Constants
// Max string length may have to be adjusted depending on data to be extracted
#define MAX_STRING_LEN  20

// Setup vars
char tagStr[MAX_STRING_LEN] = "";
char dataStr[MAX_STRING_LEN] = "";
char tmpStr[MAX_STRING_LEN] = "";
char endTag[3] = {'<', '/', '\0'};
int len;

// DECLARED VARIABLES HERE FOR GLOBAL USE
char name[MAX_STRING_LEN] = "\0";
char flavor_name[MAX_STRING_LEN] = "\0";
char mix_volume[MAX_STRING_LEN] = "\0";

// Flags to differentiate XML tags from document elements (ie. data)
boolean tagFlag = false;
boolean dataFlag = false;

// Ethernet vars
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 1, 120 };
byte server[] = { 192, 168, 1, 110 }; // My server at home

// Start ethernet client
EthernetClient client;

void setup()
{
  Serial.begin(9600);
  Serial.println("Starting WebWx");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
    // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");
  //Serial.println("connecting...");
//  Ethernet.begin(mac, ip);
  delay(5000);

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println("GET /instructions.xml HTTP/1.0");    
    client.println();
    delay(2000);
  } else {
    Serial.println("connection failed");
  }  
}

void loop() {
/*  int var = 0;
  while(var < 60){
    Serial.print("\r");
    var++;
  } */
  // Read serial data in from web:
  while (client.available()) {
    serialEvent(); 
  }
Serial.println("NAME: ");
Serial.print(name);
//Serial.println("Flavor Name: ");
//Serial.print(flavor_name);
//Serial.println("Volume to Mix: ");
//Serial.print(mix_volume);
//Serial.print("   ");
//
  if (!client.connected()) {
    //Serial.println();
    //Serial.println("Disconnected");
    client.stop();

    // Time until next update
    //Serial.println("Waiting");
    for (int t = 1; t <= 15; t++) {
      delay(60000); // 1 minute
    }

    if (client.connect(server, 80)) {
      //Serial.println("Reconnected");
      client.println("GET /instructions.xml HTTP/1.0");    
      client.println();
      delay(2000);
    } else {
      Serial.println("Reconnect failed");
    }       
  }
}

// Process each char from web
void serialEvent() {
//Serial.println("serialEvent Started");
   // Read a char
      char inChar = client.read();
   //Serial.print(".");
  
   if (inChar == '<') {
      addChar(inChar, tmpStr);
      tagFlag = true;
      dataFlag = false;

   } else if (inChar == '>') {
      addChar(inChar, tmpStr);

      if (tagFlag) {      
         strncpy(tagStr, tmpStr, strlen(tmpStr)+1);
      }

      // Clear tmp
      clearStr(tmpStr);

      tagFlag = false;
      dataFlag = true;      
      
   } else if (inChar != 10) {
      if (tagFlag) {
         // Add tag char to string
         addChar(inChar, tmpStr);

         // Check for </XML> end tag, ignore it
         if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) {
            clearStr(tmpStr);
            tagFlag = false;
            dataFlag = false;
         }
      }
      
      if (dataFlag) {
         // Add data char to string
         addChar(inChar, dataStr);
      }
   }  
  
   // If a LF, process the line
   if (inChar == 10 ) {

/*
      Serial.print("tagStr: ");
      Serial.println(tagStr);
      Serial.print("dataStr: ");
      Serial.println(dataStr);
*/
      // Find specific tags and print data
      if (matchTag("<name>")) {
//Serial.println("dataStr Length:");
//Serial.print(strlen(dataStr));
//        Serial.println("NAME: ");
//        Serial.print(dataStr[0]);

strncpy(name,dataStr,20);
name[21] = '\0';
      }
      if (matchTag("<flavor_name>")) {
         //Serial.print("   Flavor Name: ");
         //strncpy(flavor_name,dataStr,strlen(dataStr)+1);
         //Serial.print(flavor_name);
      }
      if (matchTag("<mix_volume>")) {
         //Serial.print("   Volume to Mix: ");
         //strncpy(mix_volume,dataStr,strlen(dataStr)+1);
         //Serial.print(mix_volume);
         //Serial.print("   ");
      }

      // Clear all strings
      clearStr(tmpStr);
      clearStr(tagStr);
      clearStr(dataStr);

      // Clear Flags
      tagFlag = false;
      dataFlag = false;
   }
}

/////////////////////
// Other Functions //
/////////////////////

// Function to clear a string
void clearStr (char* str) {
   int len = strlen(str);
   for (int c = 0; c < len; c++) {
      str[c] = 0;
   }
}

//Function to add a char to a string and check its length
void addChar (char ch, char* str) {
   char *tagMsg  = "<TRUNCATED_TAG>";
   char *dataMsg = "-TRUNCATED_DATA-";

   // Check the max size of the string to make sure it doesn't grow too
   // big.  If string is beyond MAX_STRING_LEN assume it is unimportant
   // and replace it with a warning message.
   if (strlen(str) > MAX_STRING_LEN - 2) {
      if (tagFlag) {
         clearStr(tagStr);
         strcpy(tagStr,tagMsg);
      }
      if (dataFlag) {
         clearStr(dataStr);
         strcpy(dataStr,dataMsg);
      }

      // Clear the temp buffer and flags to stop current processing 
      clearStr(tmpStr);
      tagFlag = false;
      dataFlag = false;

   } else {
      // Add char to string
      str[strlen(str)] = ch;
   }
}

// Function to check the current tag for a specific string
boolean matchTag (char* searchTag) {
   if ( strcmp(tagStr, searchTag) == 0 ) {
      return true;
   } else {
      return false;
   }
}

XML is incredibly verbose. I'd be concerned about running out of memory.

I too am concerned about memory. One of the reasons why I am having the arduino just pull the necessary instructions from the web as opposed to having everything(user input, calculations, options, etc) on the board.

I tried the mysql connector from Chuck's Blog: Introducing MySQL Connector/Arduino and was going to use that but I still ended up getting errors so the XML option seemed like the best one to go and pull the entire instruction set at one time.

Does anyone have any other or better recommendations?

Where is the data coming from? If you have control over the data format, I'd make your own and lean it out.