Link to home
Start Free TrialLog in
Avatar of 2bears
2bearsFlag for New Zealand

asked on

Javascript function to Parse XML file into html page

Hi Experts - I'm trying to understand how to parse XML to HTML using a Javascript function - I am quite new to this.
There are 3 files in the code window.
1. Recipe1.xml
2. Recipe.dtd
3. recipe_test.html (including the Javascript to parse and display xml to html )

My Question is:
Assuming the Recipe.DTD below is valid for the Recipe1.XML file -
What would be the correct code for the function to parse (write) the recipe into a webpage?
(I guess using XPath - I have unsuccessfully attempted to use the function  "processXPathExpression()" - starting on line 114 below but got horribly lost)

(ie. display in web page)
<h1>Title</h1>
<p>Number of Servings</p>
<p>Comment</p>
<ul>
      <li>quantity  measure    ingedient</>
      <li>quantity  measure    ingedient</>
</ul>
<p>preparation_instructions id="1"</p>
<p>preparation_instructions id="2"</p>
<p>cooking_instructions</p>

Kind regards
2bears


<?xml version="1.0" encoding="UTF-8"?>
<?xml:stylesheet type = "text/xsl" href = "recipe.xsl"?>
<!-- Recipe1.xml-->
<!DOCTYPE recipe SYSTEM "Recipe.dtd">
<recipe>
	<title created-date="2005-06-01" modified_date="2005-06-01">Fish Pie</title>
	<number_of_servings>Makes enough for one.</number_of_servings>
	<comment>Original recipe.</comment>
        <ingredients heading="Ingredients">
		<ingredient quantity="1" measure="pinch">salt</ingredient>
		<ingredient quantity="5" measure="tsp">sugar</ingredient>
		<ingredient quantity="1">fish</ingredient>
        </ingredients>
	<preparation_instructions id="1">
        Mix the sugar, salt and water and leave for about 10 minutes. 
	</preparation_instructions>
	<preparation_instructions id="2">
		Put the fish on the bench. Pour the yeast mixture onto the fish... 
	</preparation_instructions>
	<cooking_instructions>
        Cook at 280 degC for ten minutes.
	</cooking_instructions>
</recipe>
 
<!---------------------------------------- -->
 
<!-- recipe.dtd-->
 
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT recipe ((title, number_of_servings, comment, ingredients, preparation_instructions+, cooking_instructions))>
<!ELEMENT title (#PCDATA)>
<!ATTLIST title
	created-date CDATA #IMPLIED
	modified_date CDATA #IMPLIED>
<!ELEMENT number_of_servings (#PCDATA)>
<!ELEMENT comment (#PCDATA)>
<!ELEMENT ingredients ((ingredient+))>
<!ATTLIST ingredients
	heading CDATA #FIXED "Ingredients">
<!ELEMENT ingredient (#PCDATA)>
<!ATTLIST ingredient
	measure CDATA #IMPLIED
	quantity CDATA #REQUIRED>
<!ELEMENT preparation_instructions (#PCDATA)>
<!ATTLIST preparation_instructions
	id CDATA #IMPLIED>
<!ELEMENT cooking_instructions (#PCDATA)>
 
<!---------------------------------------- -->
 
<!-- recipe_test.html (containing the Javascript to parse and display xml to html) -->
 
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<!-- Locating nodes in Recipe1.xml -->
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
   <title>Parsing Recipe1.xml file using Javascript</title>
   <style type = "text/css">
		html {
		background-color: #FFFF66;	
		}
		body {
		padding:15px;
		background-color:#FFFF66;
		font-family:"Comic Sans MS", Arial, sans-serif;
		font-size:16px;
		}
		h1 {
		color:#339933;
		font-size:3em;
		}
		p {
		color:#000000;
		font-size:.75em;
		}
   </style>
   <script type = "text/javascript">
   <!--
   var doc; // variable to reference the XML document
   var outputHTML = ""; // stores text to output in outputDiv
   var browser = ""; // used to determine which browser is being used
 
   // load XML document based on whether the browser is IE7 or Firefox 2
   function loadXMLDocument( url )
   {
      if ( window.ActiveXObject ) // IE7
      {
         // create IE7-specific XML document object
         doc = new ActiveXObject( "Msxml2.DOMDocument.6.0" );
         doc.async = false; // specifies synchronous loading of XML doc
         doc.load( url ); // load the XML document specified by url
         browser = "IE7"; // set browser 
      } // end if
      else if ( document.implementation && 
         document.implementation.createDocument ) // other browsers
      {
         // create XML document object
         doc = document.implementation.createDocument( "", "", null );
         doc.load( url ); // load the XML document specified by url
         browser = "FF2"; // set browser 
      } // end else
      else // not supported
         alert( 'This script is not supported by your browser' );
   } // end function loadXMLDocument
 
   // display the XML document 
   function displayDoc()
   {
      document.getElementById( "outputDiv" ).innerHTML = outputHTML;
   } // end function displayDoc
 
   // obtain and apply XPath expression
   
    function processXPathExpression()
   {
      var xpathExpression = document.getElementById( "???" ).value;
      outputHTML = "";
 
      if ( browser == "IE7" )
      {
         var result = doc.selectNodes( xpathExpression );
 
         for ( var i = 0; i < result.length; i++ )
            outputHTML += "<div style='clear: both'>" + 
               result.item( i ).text + "</div>";
      } // end if
      else // browser == "FF2"
      {
         var result = document.evaluate( xpathExpression, doc, null, 
            XPathResult.ANY_TYPE, null );
         var current = result.iterateNext();
 
         while ( current ) 
         {
            outputHTML += "<div style='clear: both'>" + 
               current.textContent + "</div>";
            current = result.iterateNext();
         } // end while
      } // end else
 
      displayDoc();
   } // end function processXPathExpression
   </script>
</head>
<body onload = "loadXMLDocument( 'recipe_test.xml' );">
  
   <div id = "outputDiv"></div>
</body>
</html>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of dan_neal
dan_neal
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Another way to do this without any HTML or Javascript would be to use XSL(T) and just load the XML file directly.
Avatar of 2bears

ASKER

Hi Dan
Thank you for your reply.
I want to be able to use it on several recipies - ie; Recipe1.xml, Recipe2.xml etc. and display them on an individual HTML page. (I will be using/learning XSL at a later stage)
I want to see how it is parsed by using Javascript to help me learn the language.
I would be very grateful if you could give me a JS code example for this XML?
kind regards
Stephen
 
Avatar of 2bears

ASKER

P.S. The link to ee/recipe_test.htm was broken?
Rgds Stephen
Avatar of 2bears

ASKER

Hi Dan
Got access to ee/recipe_test.htm and your solution looks like it may work for me. I'll take a little time to play with it and get back shortly.
Thanks Stephen
Avatar of 2bears

ASKER

Hi Dan
The web page from your link above works and has the display I was working towards, but when I copy the code and paste it into DW or XMLSpy I lose all the data.
I have placed the file in the same (relative) directory folder as the XML and DTD but can't get it to work either using all the code from your link page or from the cleaned up version that I have attached as a code snippet.
Can't figure out what I'm missing here -
regards Stephen

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
	<!-- Locating nodes in Recipe1.xml -->
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
   <title>Parsing Recipe1.xml file using Javascript</title>
   <style type = "text/css">
		html {
		background-color: #FFFF66;	
		}
		body {
		padding:15px;
		background-color:#FFFF66;
		font-family:"Comic Sans MS", Arial, sans-serif;
		font-size:16px;
		}
		h1 {
		color:#339933;
		font-size:3em;
		}
		p, ul, li {
		color:#000000;
		font-size:.75em;
		}
   </style>
   <script type = "text/javascript">
   <!--
   var outputHTML = ""; // stores text to output in outputDiv
   var xmlDoc=null;
   
if (window.ActiveXObject)
{// code for IE
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
}
else if (document.implementation.createDocument)
{// code for Mozilla, Firefox, Opera, etc.
xmlDoc=document.implementation.createDocument("","",null);
}
else
{
alert('Your browser cannot handle this script');
}
if (xmlDoc!=null)
{
xmlDoc.async=false;
xmlDoc.load("Recipe1.xml");
// end function loadXMLDocument
 
   // display the XML document 
   function displayDoc()
   {
      document.getElementById( "outputDiv" ).innerHTML = outputHTML;
   } // end function displayDoc
 
   // obtain and apply XPath expression
   function parseXML() {
		var rt = xmlRecipe.documentElement;
		outputHTML = "";
		if(rt.hasChildNodes) {
			outputHTML = "<h1>" + rt.selectSingleNode('title').text + "</h1>"
			outputHTML += "<p>" + rt.selectSingleNode('number_of_servings').text + "</p>"
			outputHTML += "<p>" + rt.selectSingleNode('comment').text + "</p>"
			var ind = rt.selectSingleNode('ingredients')
			if(ind.hasChildNodes) {
				outputHTML += "<ul>" + ind.attributes.getNamedItem('heading').nodeValue
				for(var c = 0;c < ind.childNodes.length;c++) {
					outputHTML += "<li>" 
					if(ind.childNodes[c].attributes.getNamedItem('quantity')){
						outputHTML += ind.childNodes[c].attributes.getNamedItem('quantity').nodeValue + '&nbsp&nbsp;&nbsp;';}
					if(ind.childNodes[c].attributes.getNamedItem('measure')){
						ind.childNodes[c].attributes.getNamedItem('measure').nodeValue + '&nbsp;&nbsp;&nbsp;';}
					outputHTML += ind.childNodes[c].text + "</li>"
				}
				outputHTML += "</ul>"
			}
			var prep = rt.selectNodes('preparation_instructions')
			if(prep.length>0) {
				for(var p = 0;p < prep.length;p++) {
					outputHTML += "<p>" + prep[p].text + "</p>"
				}
			}
			outputHTML += "<p>" + rt.selectSingleNode('cooking_instructions').text + "</p>"
		}
		displayDoc();
	}
    -->
   </script>
</head>
<body onload="parseXML();">
<xml id=xmlRecipe src="Recipe1.xml"></xml>
 
   <div id="outputDiv">
	</div>
</body>
</html>

Open in new window

What is your directory structure?  if the HTML and XML do not reside in the same folder, adjust the path for the <xml> object at the beginning of the <body>.
Avatar of 2bears

ASKER

Hi Dan
Thank you for your solution and I am very happy to accept it.
After some cleaning up (backslashed out some < , / , > characters) I have only one validation error to be rid of so the page validates "xhtml1-strict"
(I have attached the final code draft as a snippet for your info)
Error message:
The tag name: "xml" Not found in currently active versions.  In the body section is <xml id="xmlRecipe" src="Recipe1.xml"></xml>
The other minor problem I can't figure out is why the 'measure' data is not showing on the webpage?
And finally, is the ' loadXMLDocument( url ) ' function for identifying the browser being loaded or called from anywhere?
If you have the time to answer these I would be very grateful.
Thank you for your time and expertise.
Kind regards Stephen

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
<!-- Locating nodes in Recipe1.xml -->
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
   <title>Parsing Recipe1.xml file using Javascript</title>
   <style type = "text/css">
		html {
		background-color: #FFFF66;	
		}
		body {
		padding:15px;
		background-color:#FFFF66;
		font-family:"Comic Sans MS", Arial, sans-serif;
		font-size:16px;
		}
		h1 {
		color:#339933;
		font-size:3em;
		}
		p {
		color:#000000;
		font-size:.75em;
		}
   </style>
   <script type = "text/javascript">
   <!--
   var doc; // variable to reference the XML document
   var outputHTML = ""; // stores text to output in outputDiv
   var browser = ""; // used to determine which browser is being used
 
   // load XML document based on whether the browser is IE7 or Firefox 2
   function loadXMLDocument( url )
   {
      if ( window.ActiveXObject ) // IE7
      {
         // create IE7-specific XML document object
         doc = new ActiveXObject( "Msxml2.DOMDocument.6.0" );
         doc.async = false; // specifies synchronous loading of XML doc
         doc.load( url ); // load the XML document specified by url
         browser = "IE7"; // set browser 
      } // end if
      else if ( document.implementation && 
         document.implementation.createDocument ) // other browsers
      {
         // create XML document object
         doc = document.implementation.createDocument( "", "", null );
         doc.load( url ); // load the XML document specified by url
         browser = "FF2"; // set browser 
      } // end else
      else // not supported
         alert( 'This script is not supported by your browser' );
   } // end function loadXMLDocument
 
   // display the XML document 
   function displayDoc()
   {
      document.getElementById( "outputDiv" ).innerHTML = outputHTML;
   } // end function displayDoc
 
   // obtain and apply XPath expression
   function parseXML() {
		var rt = xmlRecipe.documentElement;
		outputHTML = "";
		if(rt.hasChildNodes) {
			outputHTML = "\<h1\>" + rt.selectSingleNode('title').text + "\<\/h1\>"
			outputHTML += "\<p\>" + rt.selectSingleNode('number_of_servings').text + "\<\/p\>"
			outputHTML += "\<p\>" + rt.selectSingleNode('comment').text + "\<\/p\>"
			var ind = rt.selectSingleNode('ingredients')
			if(ind.hasChildNodes) {
				outputHTML += "<ul>" + ind.attributes.getNamedItem('heading').nodeValue
				for(var c = 0;c < ind.childNodes.length;c++) {
					outputHTML += "<li>" 
					if(ind.childNodes[c].attributes.getNamedItem('quantity')){
						outputHTML += ind.childNodes[c].attributes.getNamedItem('quantity').nodeValue + '&nbsp&nbsp;&nbsp;';}
					if(ind.childNodes[c].attributes.getNamedItem('measure')){
						ind.childNodes[c].attributes.getNamedItem('measure').nodeValue + '&nbsp;&nbsp;&nbsp;';}
					outputHTML += ind.childNodes[c].text + "\<\/li\>"
				}
				outputHTML += "\<\/ul\>"
			}
			var prep = rt.selectNodes('preparation_instructions')
			if(prep.length>0) {
				for(var p = 0;p < prep.length;p++) {
					outputHTML += "\<p\>" + prep[p].text + "\<\/p\>"
				}
			}
			outputHTML += "\<p\>" + rt.selectSingleNode('cooking_instructions').text + "\<\/p\>"
		}
		displayDoc();
	}
 
-->
   </script>
</head>
 
<body onload="parseXML();">
<xml id="xmlRecipe" src="Recipe1.xml"></xml>
   <div id="outputDiv">
	
	</div>
</body>
</html>

Open in new window

Avatar of 2bears

ASKER

Excellent respose and solution.