// A very basic XML Parser written in LSL. // global variables for reading, holding, and handling the initial XML read string xmlFileName = "xml-test"; string xmlBody = ""; integer xmlBodyLine = 0; key xmlBodyKey; // Chops off the string up to the first, found element // xml - XML string // start - where the llSubStringIndex begins // offset - the length to the right the substring needs to begin string llReadTo(string xml, integer start, integer offset) { integer ReadTo = start + offset; return llGetSubString(xml, ReadTo, -1); } // Returns the inner text of a node. string llGetNodeText(string xml, string nodeName) { string elStart = "<" + nodeName; string elStop = ""; integer elCloseTag = llSubStringIndex(xml, elStop); integer elOpenTag = llSubStringIndex(xml, "/>"); // There has to be some kind of closing tag for the parsing to be valid if (elCloseTag != -1 || elOpenTag != -1) { // For: ... if (llSubStringIndex(xml, elStart) != -1 && (elCloseTag < elOpenTag || elOpenTag == -1)) { integer nodeStart = llSubStringIndex(xml, elStart) + llStringLength(elStart) + 1; integer nodeStop = llSubStringIndex(xml, elStop) - 1; string nodeText = llGetSubString(xml, nodeStart, nodeStop); return nodeText; } // For: else if (llSubStringIndex(xml, elStart) != -1 && (elCloseTag > elOpenTag || elCloseTag == -1)) { integer nodeStart = llSubStringIndex(xml, elStart) + llStringLength(elStart) + 1; integer nodeStop = llSubStringIndex(xml, "/>") - 1; string nodeText = llGetSubString(xml, nodeStart, nodeStop); return nodeText; } // For: invalid XML else { return ""; } } else { return ""; } } // Counts the number of nodes in a string integer llCountElements(string xml, string nodeName) { string elStart = "<" + nodeName; integer elStartLen = llStringLength(elStart) + 1; integer nodeCount = 0; while (llSubStringIndex(xml, elStart) != -1) { // Increments node count ++nodeCount; // Chops off the string up to the first, found element xml = llReadTo(xml, llSubStringIndex(xml, elStart), elStartLen); } return nodeCount; } // Checks for attributes in an element list llGetElementAttributes(string xml) { integer elTagEnd = 0; if (llSubStringIndex(xml, "/>") == -1) { elTagEnd = llSubStringIndex(xml, ">") - 1; } else { if (llSubStringIndex(xml, " />") == -1) { elTagEnd = llSubStringIndex(xml, "/>") - 1; } else { elTagEnd = llSubStringIndex(xml, "/>") - 2; } } xml = llGetSubString(xml, 0, elTagEnd); list attributes = llParseString2List(xml, ["=\"", "\""], []); return attributes; } // Gets an attribute value, based of an attribute's name, from apaired list string llGetAttributeValue(list attributes, string name) { string value = ""; integer isName = 0; integer isCntr = 0; // isName is switched to 1 when the loop finds a list valuen with the attribute name // in the next iteration, the next list value is assigned to the variable "value" // and isName is reset to 0 while (llList2String(attributes, isCntr) != "") { if (isName == 1) { value = llList2String(attributes, isCntr); isName = 0; } else { if ((isCntr % 2) == 0) { string temp = llList2String(attributes, isCntr); if (llGetSubString(temp, 0, 0) == " ") { temp = llGetSubString(temp, 1, -1); } if (temp == name) { isName = 1; } } } isCntr++; } return value; } // Gets a list of nodes list llGetNodeList(string xml, string nodeName) { list nodeList; integer elementCount = llCountElements(xml, nodeName); // If nodes exist with the XML string, proceed if (elementCount > 0) { integer nodeCntr; for (nodeCntr = 0; nodeCntr < elementCount; nodeCntr++) { string tempText = llGetNodeText(xml, nodeName); nodeList = nodeList + [tempText]; xml = llReadTo(xml, llSubStringIndex(xml, tempText), llStringLength(tempText)); xml = llGetSubString(xml, llSubStringIndex(xml, "<" + nodeName), -1); } } // If there are no such nodes in the string, return a one element // list with "No nodes" inside. else { nodeList = ["No nodes"]; } return nodeList; } // This has to be here default { state_entry() { if (xmlBody == "") { state readfile; } else { llSay(0, xmlBody); } } touch_start(integer total_number) { list spies = llGetNodeList(xmlBody, "spy"); integer spyCntr = 0; while (llList2String(spies, spyCntr) != "") { string xmlTemp = llList2String(spies, spyCntr); list spyName = llGetElementAttributes(xmlTemp); string hairSpy = llGetAttributeValue(spyName, "hair"); string lenSpy = llGetAttributeValue(spyName, "length"); string nameSpy = llGetAttributeValue(spyName, "name"); string color = llGetNodeText(xmlTemp, "suit"); llSay(0, nameSpy + " has a " + color + " uniform and " + lenSpy + ", " + hairSpy + " hair."); ++spyCntr; } } } // This simply reads XML from a Notecard. // This can be removed when grabbing information from the web. state readfile { state_entry() { // Makes sure xmlBody is empty xmlBody = ""; // Starts the reading of the notecard xmlBodyKey = llGetNotecardLine(xmlFileName, xmlBodyLine); } dataserver(key query_id, string data) { if (query_id == xmlBodyKey) { // Perform the following while there is text if (data != EOF) { // Removes leading spaces or tabs if (llSubStringIndex(data, "<") > 0) { data = llDeleteSubString(data, 0, (llSubStringIndex(data, "<") - 1)); } // Appends the next line to xmlBody xmlBody = xmlBody + data; // Increments the line counter ++xmlBodyLine; // Reads the next line xmlBodyKey = llGetNotecardLine(xmlFileName, xmlBodyLine); } // If you've gotten to the end of the notecard, go back else { state default; } } } state_exit() { xmlBodyLine = 0; } }