Welcome to the IJIS Technical Advisory Committee (ITAC) Guides website. This site has been established to help promote and communicate information surrounding the usage and implementation of the National Information Exchange Model (NIEM). It serves as a document archive for the committee. If you have any questions surrounding NIEM, please do not hesitate to contact the National Information Sharing Standards (NISS) Helpdesk at NISShelp@ijis.org

Thursday, October 10, 2013

jQuery: Download XML from a Static URL

The jQuery library has a robust set of capabilities when it comes to accessing documents and data through HTTP.  One of the simplest scenarios for accessing XML data is from a static, or unchanging URL.  For example, if a NIEM XML code list is stored at a fixed location it may be useful to access it directly from a web-page and display the results in a choice box or list for users to select from.  This allows for content to be dynamic without directly editing or updating the web page each time a list of codes is changed.  This is the scenario the remainder of this guide will focus on.

Step 1: Include jQuery Library

The first step in leveraging jQuery is actually including the appropriate library on your web-page. There are both compressed and uncompressed versions of this library available on jquery.com and in many cases you can simply link to a hosted copy of the library on the web. For this exercise, let's assume we have a copy of the library hosted on the same server (and in the same directory) as the html page we're writing. In this case, we will include the script by using the following:

<!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
<script src="jquery-1.10.2.js"></script>
  

Step 2: ‘Get’ XML from the URL - As Text (Optional)


jQuery provides a very powerful and flexible .ajax command to allow developers to make HTTP GET and HTTP POST calls with support for both success and error conditions.  In reality, jQuery is merely masking a series of JavaScript calls that would be required to support doing these same functions (thereby shrinking the footprint of our code and increasing its readability significantly). 


For the purposes of learning, we will first bring back the XML found in a URL location as text and display it in a text field on the screen.  This is a good first step to ensure we have the proper URL and the XML stored there appears to be correct.  Often you will use this for debugging or logging purposes only though.  The following snippet allows us to access the URL passed into a function.

function getXmlFromUrl(sUrl) {
    //Retrieve the XML simply for display using dataType:'text'
    $.ajax({
        type: "GET",
        url: sUrl,
        dataType: "text",
        error: function(err){
            alert("Error accessing TEXT file |" + sUrl + "|");
        },
        success: function (text) {
            textField.value = text;
        }
    });
}

In the above, when a URL is successfully accessed, the “success:” function is called, and in this  case, the text stored in the URL is placed into a Text Area (with an ID of ‘textField’ in this example) on the screen. 


Step 3: ‘Get’ XML from the URL - As XML


The same .ajax command used in the above text example is also used to obtain XML with a few minor modifications.  To get an XML object back from the URL instead of raw text, the dataType: is changed to ‘xml’ and the success: function must handle and process the return results very differently.  The differences are shown in the following snippet:

$.ajax({
     type: "GET",
     url: sUrl,
     dataType: "xml",
     error: function (err) {
         alert("Error accessing XML file |" + sUrl + "|");
     },
     success: function (xml) {
         //find all simpleType nodes in the document
         $(xml).find("xsd\\:simpleType, simpleType").each(function () {
             //only looking for the EYECodeSimpleType for now
             if ($(this).attr("name") == "EYECodeSimpleType") {
                 //loop through each enumeration
                 $(this).find("xsd\\:enumeration, enumeration").each(function () {
                     //add to dropdown HTML <select> object
                     $("#selectBox").append("<option value='" + $(this).attr("value") + "'>" + $(this).find("xsd\\:documentation, documentation").text() + "</option>");
                 });
             }
         });
     }
});

jQuery (and it’s cousin JavaScript) is not known for handling of XPath, and to that end, it leverages CSS selectors instead of XPath statements commonly used in compiled languages and XSLT.  Knowing that, further inspection of the success: function is probably required. 


In order to find the enumerations of eye color, we use the .find() function in the following format:

$(xml).find(“namespacePrefix\\:elementName, elementName) //The \\: is an escape sequenced colon.

As discussed in the jQuery Parse XML guide, two different strings are listed as find criteria, one with the namespace prefix (required by Microsoft Internet Explorer) and one omitting the prefix (as required by Web-Kit-Based browsers).  This brings back a series of nodes, which are then looped through using the each() function in the following format:

nodeListResults.each(function(){ //do something here with each node });

In order to know we have the right node selected, a second nested .find() function is called on each node within the each “loop”.  In this case, we’re only looking for the element named “EYECodeSimpleType” and skip any other simpleType node that is not named this.  We use the .attr() function to return the “name” attribute of each node using the following:

if ($(this).attr(“name”) == “EYECodeSimpleType”) { //do something with EYECodeSimpleType node }

Finally, all the “enumeration” elements of the matching simple data type are compiled and we use a nested each() “loop” to add an option to a select box on the page. 


Final: Full Example


The following is a full HTML and jQuery listing of the source used in this guide.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>jQuery HTTP Get Example</title>

    <!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
    <script src="jquery-1.10.2.js"></script>

    <!-- On Page JavaScript -->
    <script>
        function getXmlFromUrl(sUrl) {

            //Retrieve the XML simply for display using dataType:'text'
            $.ajax({
                type: "GET",
                url: sUrl,
                dataType: "text",
                error: function (err) {
                    alert("Error accessing TEXT file |" + sUrl + "|");
                },
                success: function (text) {
                    textField.value = text;
                }
            });

            //Retrieve the XML for code list enforcement using dataType:'xml'
            $.ajax({
                type: "GET",
                url: sUrl,
                dataType: "xml",
                error: function (err) {
                    alert("Error accessing XML file |" + sUrl + "|");
                },
                success: function (xml) {
                    //find all simpleType nodes in the document
                    $(xml).find("xsd\\:simpleType, simpleType").each(function () {

                        //only looking for the EYECodeSimpleType for now
                        if ($(this).attr("name") == "EYECodeSimpleType") {

                            //loop through each enumeration
                            $(this).find("xsd\\:enumeration, enumeration").each(function () {

                                //add to dropdown HTML <select> object
                                $("#selectBox").append("<option value='" + $(this).attr("value") + "'>" + $(this).find("xsd\\:documentation, documentation").text() + "</option>");
                            });

                        }
                    });
                }
            });
        }
    
        function selectedValue() {
            //post the selected value in an alert box
            alert($("#selectBox :selected").attr("value"));
        }
        
        
    </script>

</head>
<body>

    <p style="font-family:'Segoe UI'">
        Click on the "Get XML" button to retrieve text from the file "fbi.xsd"
    </p>

    <textarea id="textField" style="width:100%;height:100px"></textarea>
    <select id="selectBox" onchange="selectedValue()">
        <option value="None">None</option>
    </select>

    <p><button id="go" onclick="getXmlFromUrl('./Subset/niem/fbi/2.0/fbi.xsd')">Get XML</button></p>
    
</body>
</html>

    
        function selectedValue() {
            //post the selected value in an alert box
            alert($("#selectBox :selected").attr("value"));
        }
        
        
    </script>

</head>
<body>

    <p style="font-family:'Segoe UI'">
        Click on the "Get XML" button to retrieve text from the file "./example.xml"
    </p>

    <textarea id="textField" style="width:100%;height:100px"></textarea>
    <select id="selectBox" onchange="selectedValue()">
        <option value="None">None</option>
    </select>

    <p><button id="go" onclick="getXmlFromUrl('./Subset/niem/fbi/2.0/fbi.xsd')">Get XML</button></p>
    
</body>
</html>


Extra: Live Demo


A working example of the above example can be found here.

Monday, October 7, 2013

jQuery: Parse XML

The jQuery series of articles will look at how to leverage jQuery to access and manipulate NIEM-conformant XML payloads. This article looks simply at the capability to access, parse and read the data contained in a nc:AddressFullText element, strip whitespace from it, and place it in a text area on a web page. Later articles will explain how to handle multiple occurrences of a single element and eventually map the address on a webpage.

jQuery is a powerful scripting tool used by many modern developers in creating and processing web pages. We will be using it as a client-side script where the user's browser is working on an XML stream directly without doing work on a server. This is one approach to leveraging the power of a client's own browser in the current "AJAX" development stagey.

Step 1: Include jQuery Library

The first step in leveraging jQuery is actually including the appropriate library on your web-page. There are both compressed and uncompressed versions of this library available on jquery.com and in many cases you can simply link to a hosted copy of the library on the web. For this exercise, let's assume we have a copy of the library hosted on the same server (and in the same directory) as the html page we're writing. In this case, we will include the script by using the following:

<!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
<script src="jquery-1.10.2.js"></script>
 
 

Step 2: Parse XML from a String


With the library included on our HTML page, we can access all the features available to us within our on-page JavaScript. In order to use a stream of XML data, we'll need to first parse it. in jQuery we simply use the $.parseXML(string) command. This will return for us a parsed XML document. As we don't want our users to receive unhandled exceptions, and there is never a guarantee the XML we process is without error, we want to be sure to use try/catch when parsing our file. Here is what the snippet of parsing would look like:

//the try & catch block support for .parseXML() requies jQuery 1.9 or newer!
try{
var xmlDoc = $.parseXML(xml);
var $xml = $(xmlDoc);
} catch (err) {
alert("Error parsing XML! Likely invalid XML or undefined namespace prefix.");
return;
}
 

Step 3: Locate/Find Desired Node


Once we have successfully parsed the XML document, we can access portions of the document using a number of jQuery-supported methods. One of the simplest methods (and the one we will use today) is the xmlDocument.find('pattern') method. It simply returns an element [array] for all the elements it finds that match the pattern passed into the function. For example, if we want to "find" all of the elements called PersonName, we would simply pass it 'PersonName'. Here, we will assume we're working with nc:Address elements that contain plain text addresses and our expanded code will look something like this:

$address = $xml.find("nc\\:AddressFullText, AddressFullText");


You will notice we passed in two parameters. This is to work around a compatibility issue between Web-Kit-Based Browsers (Chrome, Firefox, Safari, etc.) and Microsoft Internet Explorer (IE). IE allows us to use an escape-sequenced colon to define our element prefix (\\:), however the Web-Kit browsers do not. By passing it both a prefixed and simple element name, both browser types will accept and process the find properly.


Step 4: Cleanup Whitespace (optional)


Since we are processing a plain text field, we will likely have some extra whitespace (spaces and line-feeds) that we don't want. We can simply use a string.replace('pattern') with a regex to clear out what we don't want and save the text value contained in our element by using the .text() method as shown in the following.

//Clear Whitespaces and save text value of the element in a string variable
textAddress = $address.text().replace(/^(\s*)|(\s*)$/g, '').replace(/\s+/g, ' ');
 

Final: Full Example


Once we have the value saved in a variable, we can now use it in any way we want directly in our script. The following is the full HTML and JavaScript/jQuery code for this example including a text field for entering NIEM-conformant XML and a text field for the parsed data.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>nc:Address jQuery Parse Example</title>

<!-- jQuery Include (change to match the file name and location where you have the jQuery library stored) -->
<script src="jquery-1.10.2.js"></script>

<!-- On Page JavaScript -->
<script>

function resolveAddress() {
var textAddress;
var $address;
var xml = textField.value;

//the try & catch block support for .parseXML() requies jQuery 1.9 or newer!
try{
var xmlDoc = $.parseXML(xml);
var $xml = $(xmlDoc);
} catch (err) {
alert("Error parsing XML! Likely invalid XML or undefined namespace prefix.");
return;
}

//jQuery .find()
//find any and all values stored in the (possibly repeating) element nc:AddressFullText
//The following returns an ELEMENT and requires we use .text() to access the return value
$address = $xml.find("nc\\:AddressFullText, AddressFullText");
//Clear Whitespaces
textAddress = $address.text().replace(/^(\s*)|(\s*)$/g, '').replace(/\s+/g, ' ');
//Output Value
textFindOutput.value = textAddress;


}
</script>

</head>
<body>
<div>
<p style="font-family:'Segoe UI'">
Enter or paste in a valid nc:Address block and click on the "Parse Data" button.
</p>

<textarea id="textField" style="width:100%;height:100px">
<myExchange xmlns:nc='http://niem.gov/niem/niem-core/2.0'>
<nc:Address>
<nc:AddressFullText>
One Microsoft Way
Redmond, WA 98052
</nc:AddressFullText>
</nc:Address>
</myExchange>
</textarea>

<p><button id="go" onclick="resolveAddress()">Parse Data</button></p>
</div>
<div>
<p style="font-family:'Segoe UI'">jQuery .find("nc\\:AddressFullText") using .text() to access the <u>text</u> found.</p>
<textarea id="textFindOutput" style="width:100%;height:100px"></textarea>
</div>



</body>
</html>

 


Extra: Live Demo


Additionally, you can simply access a sample of this code working here.