Search code examples
xmlactionscript-3searchxmllist

as3 search xml with multiple elements


I'm trying to search this XML document in as3

<mineral>
    <name>Calcite</name>
    <color>White</color
    <diaphaneity>Opaque</diaphaneity>
</mineral>
<mineral>
    <name>Spangolite</name>
    <color>Blue</color>
    <color>Green</color>
    <color>Blue Green</color>
    <color>Dark Green</color>
    <color>Emerald Green</color>
    <diaphaneity>Transparent</diaphaneity>
    <diaphaneity>Translucent</diaphaneity>
</mineral>
<mineral>
    <name>Barite</name>
    <color>Yellow</color>
    <color>Honey</color>
    <diaphaneity>Transparent</diaphaneity>
    <diaphaneity>Translucent</diaphaneity>
    <diaphaneity>Opaque</diaphaneity>
</mineral>
<mineral>
    <name>Landauite</name>
    <color>White</color>
    <diaphaneity>Transparent</diaphaneity>
    <diaphaneity>Translucent</diaphaneity>
</mineral>
<mineral>
    <name>Sapphire</name>
    <color>Blue</color>
    <color>Blue green</color>
    <diaphaneity>Transparent</diaphaneity>
    <diaphaneity>Translucent</diaphaneity>
</mineral>

and filter the results by Color first. So if you search for "Blue" you will get results of all the minerals that contain a "color" element who's value is "Blue" (Spangolite and Sapphire).

I load in my XML and create an XMLList of all the elements.

var dataLoader:URLLoader = new URLLoader();
var xmlData:XML;
dataLoader.addEventListener(Event.COMPLETE, LoadComplete); 
dataLoader.load(new URLRequest("mineralXML.xml"));
function LoadComplete(e:Event):void
{
     xmlData = new XML(e.target.data);
     ParseMinerals(xmlData);
}

function ParseMinerals(mineralXML:XML):void
{
     var  mineralList:XMLList  =  mineralXML.mineral;

trace(mineralList);
}

With the "trace(mineralList)" command it will successfully trace the entire XML file, and if I change it to "trace(xmlData.mineral.(color == "White"));" then it traces out all of the nodes that a element with the value of "White".

<mineral>
  <name>Calcite</name>
  <color>White</color>
  <diaphaneity>Opaque</diaphaneity>
</mineral>
<mineral>
  <name>Landauite</name>
  <color>White</color>
  <diaphaneity>Transparent</diaphaneity>
  <diaphaneity>Translucent</diaphaneity>
</mineral>

However, if I search for Blue instead of White, it doesn't trace out anything. I'm guessing this is because the mineral nodes containing a element with values of "Blue" also have multiple other color values. This is the problem I am trying to assess.

I need to be able to search for a color and pull out all of the nodes that have one of those color values, regardless of having other color values.


Solution

  • I actually achieved this with the following code:

    first I made an array for the results to be contained in when they are defined as well as a variable to note which result number the loop was at

    var resultArray:Array = new Array;
    var resultNum:Number = 0;
    

    then I made a shared object out of the XML data

    function ParseMinerals(mineralXML:XML):void
    {
         //create a var called memory and datatype it to SharedObject and name the
         //file "attributes"
         var memory:SharedObject = SharedObject.getLocal("attributes");
    
         //create an XMLList containing the information in mineralXML.mineral
         var  mineralList:XMLList  =  mineralXML.mineral;
    
         //save the data in mineralList to shared object
         memory.data.mineralList = mineralList;
         memory.flush();
    }
    

    instead of running the code after the xml was loaded in the ParseMinerals function, I put it in a new function called "search" which runs when you push the "search" button.

    function search(event:MouseEvent):void
    {
        //load shared file
        var memory:SharedObject = SharedObject.getLocal("attributes");
    
        //create a variable that is the length of the list of minerals
        var len:int = memory.data.mineralList.length();
    
        //create variables to temporarily store information regarding minerals color 
        //and name
        var thisColor:String;
        var thisName:String;
    
        //create var that increments for each time you loop through a "mineral" node
        for (var i:int = 0; i < len; i++) {
            //create var that increments for each time you loop through a "color"
            //element  within a single "mineral" node
            for (var c:int = 0; c < xmlData.mineral[i].color.length(); c++) {
                //make thisColor equal to the current color that the for loop is on
                thisColor = xmlData.mineral[i].color[c];
                //make thisName equal to the current name that the for loop is on
                thisName = xmlData.mineral[i].name;
                //if the color that the for loop is currently on is equal to the
                //color you are searching for...
                if (thisColor == memory.data.mineralColor){
                    //... then put the name of that mineral into an array
                    resultArray.push(thisName);
                    //... add 1 to the current result number
                    resultNum ++;
                    //... and trace the current result number and the name of the
                    //... mineral corresponding to the color you are searching for
                    trace("Result #" + resultNum + ": " + (thisName));
                }
            }
        }
        //reset array
        resultArray.length = 0;
    
        //reset result number
        resultNum = 0;
    }
    

    I'm not sure if this is the most efficient way to achieve the goal, but it works. If I select "White" from the list and click the Search button I made, the program traces

    Result #1: Calcite 
    Calcite
    

    and if I search for "Blue" then the program traces

    Result #1: Spangolite
    Result #2: Sapphire
    Spangolite, Sapphire
    

    I hope this helps anybody that is trying to achieve a similar goal.