document.implementation.createDocument()
MSXML2.DOMDocument
. /** * Create a new Document object. If no arguments are specified, * the document will be empty. If a root tag is specified, the document * will contain that single root tag. If the root tag has a namespace * prefix, the second argument must specify the URL that identifies the * namespace. */ XML.newDocument = function(rootTagName, namespaceURL) { if (!rootTagName) rootTagName = ""; if (!namespaceURL) namespaceURL = ""; if (document.implementation && document.implementation.createDocument) { // This is the W3C standard way to do it return document.implementation.createDocument(namespaceURL, rootTagName, null); } else { // This is the IE way to do it // Create an empty document as an ActiveX object // If there is no root element, this is all we have to do var doc = new ActiveXObject("MSXML2.DOMDocument"); // If there is a root tag, initialize the document if (rootTagName) { // Look for a namespace prefix var prefix = ""; var tagname = rootTagName; var p = rootTagName.indexOf(':'); if (p != -1) { prefix = rootTagName.substring(0, p); tagname = rootTagName.substring(p+1); } // If we have a namespace, we must have a namespace prefix // If we don't have a namespace, we discard any prefix if (namespaceURL) { if (!prefix) prefix = "a0"; // What Firefox uses } else prefix = ""; // Create the root element (with optional namespace) as a // string of text var text = "<" + (prefix?(prefix+":"):"") + tagname + (namespaceURL ?(" xmlns:" + prefix + '="' + namespaceURL +'"') :"") + "/>"; // And parse that text into the empty document doc.loadXML(text); } return doc; } };
load()
method. /** * Synchronously load the XML document at the specified URL and * return it as a Document object */ XML.load = function(url) { // Create a new document the previously defined function var xmldoc = XML.newDocument(); xmldoc.async = false; // We want to load synchronously xmldoc.load(url); // Load and parse return xmldoc; // Return the document };
/** * Asynchronously load and parse an XML document from the specified URL. * When the document is ready, pass it to the specified callback function. * This function returns immediately with no return value. */ XML.loadAsync = function(url, callback) { var xmldoc = XML.newDocument(); // If we created the XML document using createDocument, use // onload to determine when it is loaded if (document.implementation && document.implementation.createDocument) { xmldoc.onload = function() { callback(xmldoc); }; } // Otherwise, use onreadystatechange as with XMLHttpRequest else { xmldoc.onreadystatechange = function() { if (xmldoc.readyState == 4) callback(xmldoc); }; } // Now go start the download and parsing xmldoc.load(url); };
/** * Parse the XML document contained in the string argument and return * a Document object that represents it. */ XML.parse = function(text) { if (typeof DOMParser != "ftp://ftp.") { // Mozilla, Firefox, and related browsers return (new DOMParser()).parseFromString(text, "application/xml"); } else if (typeof ActiveXObject != "undefined") { // Internet Explorer. var doc = XML.newDocument(); // Create an empty document doc.loadXML(text); // Parse text into it return doc; // Return it } else { // As a last resort, try loading the document from a data: URL // This is supposed to work in Safari. Thanks to Manos Batsis and // his Sarissa library (sarissa.sourceforge.net) for this technique. var url = "data:text/xml;charset=utf-8," + encodeURIComponent(text); var request = new XMLHttpRequest(); request.open("GET", url, false); request.send(null); return request.responseXML; } };
getElementById
only works if the attribute is
of type “id” as specified in the xsd (XML
Schema Definition) or DTD (works for me in Firefox with XHTML).getAttribute()
and
setAttribute()
. You cannot use properties to
access attributes./** * Extract data from the specified XML document and format it as an HTML table. * Append the table to the specified HTML element. (If element is a string, * it is taken as an element ID, and the named element is looked up.) * * The schema argument is a JavaScript object that specifies what data is to * be extracted and how it is to be displayed. The schema object must have a * property named "rowtag" that specifies the tag name of the XML elements that * contain the data for one row of the table. The schema object must also have * a property named "columns" that refers to an array. The elements of this * array specify the order and content of the columns of the table. Each * array element may be a string or a JavaScript object. If an element is a * string, that string is used as the tag name of the XML element that contains * table data for the column, and also as the column header for the column. * If an element of the columns[] array is an object, it must have one property * named "tagname" and one named "label". The tagname property is used to * extract data from the XML document and the label property is used as the * column header text. If the tagname begins with an @ character, it is * an attribute of the row element rather than a child of the row. */ function makeTable(xmldoc, schema, element) { // Create the <table> element var table = document.createElement("table"); // Create the header row of <th> elements in a <tr> in a <thead> var thead = document.createElement("thead"); var header = document.createElement("tr"); for(var i = 0; i < schema.columns.length; i++) { var c = schema.columns[i]; var label = (typeof c == "string")?c:c.label; var cell = document.createElement("th"); cell.appendChild(document.createTextNode(label)); header.appendChild(cell); } // Put the header into the table thead.appendChild(header); table.appendChild(thead); // The remaining rows of the table go in a <tbody> var tbody = document.createElement("tbody"); table.appendChild(tbody); // Now get the elements that contain our data from the xml document var xmlrows = xmldoc.getElementsByTagName(schema.rowtag); // Loop through these elements. Each one contains a row of the table for(var r=0; r < xmlrows.length; r++) { // This is the XML element that holds the data for the row var xmlrow = xmlrows[r]; // Create an HTML element to display the data in the row var row = document.createElement("tr"); // Loop through the columns specified by the schema object for(var c = 0; c < schema.columns.length; c++) { var sc = schema.columns[c]; var tagname = (typeof sc == "string")?sc:sc.tagname; var celltext; if (tagname.charAt(0) == '@') { // If the tagname begins with '@', it is an attribute name celltext = xmlrow.getAttribute(tagname.substring(1)); } else { // Find the XML element that holds the data for this column var xmlcell = xmlrow.getElementsByTagName(tagname)[0]; // Assume that element has a text node as its first child var celltext = xmlcell.firstChild.data; } // Create the HTML element for this cell var cell = document.createElement("td"); // Put the text data into the HTML cell cell.appendChild(document.createTextNode(celltext)); // Add the cell to the row row.appendChild(cell); } // And add the row to the tbody of the table tbody.appendChild(row); } // Set an HTML attribute on the table element by setting a property. // Note that in XML we must use setAttribute() instead. table.frame = "border"; // Now that we've created the HTML table, add it to the specified element. // If that element is a string, assume it is an element ID. if (typeof element == "string") element = document.getElementById(element); element.appendChild(table); }
function displayAddressBook(){ var schema = { rowtag: "contact", columns: [ {tagname: "@name", label: "Name"}, {tagname: "email", label: "Address"} ] }; var xmldoc = XML.load("addresses.xml"); makeTable(xmldoc, schema, "addresses"); }addresses.xml:
<?xml version="1.0" encoding="ISO-8859-1"?> <contacts> <contact name="Able Baker"><email>able@example.com</email></contact> <contact name="Careful Dodger"><email>dodger@example.com</email></contact> <contact name="Eager Framer" personal="true"><email>framer@example.com</email></contact> </contacts><div id="addresses"><!--table here--> </div>
XSLTProcessor
object while IE has
document.transformNode()
method. <?xml version="1.0"?><!-- this is an xml document --> <!-- declare the xsl namespace to distinguish xsl tags from html tags --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <!-- When we see the root element, output the HTML framework of a table --> <xsl:template match="/"> <table> <tr><th>Name</th><th>E-mail Address</th></tr> <xsl:apply-templates/> <!-- and recurse for other templates --> </table> </xsl:template> <!-- When we see a <contact> element... --> <xsl:template match="contact"> <tr> <!-- Begin a new row of the table --> <!-- Use the name attribute of the contact as the first column --> <td><xsl:value-of select="@name"/></td> <xsl:apply-templates/> <!-- and recurse for other templates --> </tr> </xsl:template> <!-- When we see an <email> element, output its content in another cell --> <xsl:template match="email"> <td><xsl:value-of select="."/></td> </xsl:template> </xsl:stylesheet>
<?xml version="1.0" encoding="ISO-8859-1" ?> <?xml-stylesheet type="text/xsl" href="./feedtohtml.xsl" ?> <myrss> <!--changed from rss because firefox is too smart and asks me if I want to subscribe. --> <channel xmlns:html="http://www.w3.org/1999/xhtml"> <title>CSCE 782: Fall 2006</title> <link>http://jmvidal.cse.sc.edu/csce782/</link> <description>Announcements.</description> <language>en-us</language> <copyright>Copyright 2006 jmvidal</copyright> <docs>http://blogs.law.harvard.edu/tech/rss/</docs> <lastBuildDate>Mon, 04 Dec 2006 15:16:10 EST</lastBuildDate> <item> <title>Final Project Handout</title> <pubDate>Mon, 04 Dec 2006 15:14:42 EST</pubDate> <guid>http://jmvidal.cse.sc.edu/csce782/news.rss#1165263282</guid> <description> OK, I have posted the final project handout. Let me know if you have questions. </description> <link>http://jmvidal.cse.sc.edu/csce782/news.rss</link> </item> <item> <title>Last Week: No Classes</title> <pubDate>Thu, 30 Nov 2006 09:06:43 EST</pubDate> <guid>http://jmvidal.cse.sc.edu/csce782/news.rss#1164895603</guid> <description> We will not be meeting during the last week. But, I will be in my office during class time in case you want to talk about your final project. </description> <link>http://jmvidal.cse.sc.edu/csce782/news.rss</link> </item> <item> <title>Test 2</title> <pubDate>Tue, 28 Nov 2006 06:40:37 EST</pubDate> <guid>http://jmvidal.cse.sc.edu/csce782/news.rss#1164714037</guid> <description> In case I did not mention it in class, Test 2 will be based solely on the rest of the book chapters. That is, it does not cover the papers I presented in class. </description> <link>http://jmvidal.cse.sc.edu/csce782/news.rss</link> </item> </channel> </myrss>feedtohtml.xsl:
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/myrss"> <html> <head> <link href="xsl.css" rel="stylesheet" type="text/css" /> <style type="text/css"> body { font-size:0.83em; } </style> </head> <body> <div id="logo"> <xsl:element name="a"> <xsl:attribute name="href"> <xsl:value-of select="channel/link" /> </xsl:attribute> <xsl:value-of select="channel/title" /> </xsl:element> </div> <div class="Snippet" style="border-width:0; background-color:#FFF; margin:1em"> <div class="titleWithLine"> <xsl:value-of select="channel/description" /> </div> <dl style="padding-right:1em"> <xsl:for-each select="channel/item"> <dd> <xsl:value-of select="title"/> </dd> <dt> <xsl:value-of select="description" disable-output-escaping="yes"/><br /> <span class="comments"><xsl:value-of select="pubDate" /></span> </dt> </xsl:for-each> </dl> </div> <div id="footer"> <xsl:value-of select="channel/copyright" /> </div> </body> </html> </xsl:template> </xsl:stylesheet>
<?xml version="1.0" encoding="ISO-8859-1"?> <contacts> <contact name="Able Baker"><email>able@example.com</email></contact> <contact name="Careful Dodger"><email>dodger@example.com</email></contact> <contact name="Eager Framer" personal="true"><email>framer@example.com</email></contact> </contacts>Let context = contacts:
contact
set of all <contact> tags.contact[1]
first <contact> tag.contact[last()]
last <contact> tag.contact/email
all <email> children of <contact>contact/@name
value of name attribute of contact childrencontact[@personal="true"]
all <contact> tags with attribute personal = "true"/** * XML.XPathExpression is a class that encapsulates an XPath query and its * associated namespace prefix-to-URL mapping. Once an XML.XPathExpression * object has been created, it can be evaluated one or more times (in one * or more contexts) using the getNode() or getNodes() methods. * * The first argument to this constructor is the text of the XPath expression. * * If the expression includes any XML namespaces, the second argument must * be a JavaScript object that maps namespace prefixes to the URLs that define * those namespaces. The properties of this object are the prefixes, and * the values of those properties are the URLs. */ XML.XPathExpression = function(xpathText, namespaces) { this.xpathText = xpathText; // Save the text of the expression this.namespaces = namespaces; // And the namespace mapping if (document.createExpression) { // If we're in a W3C-compliant browser, use the W3C API // to compile the text of the XPath query this.xpathExpr = document.createExpression(xpathText, // This function is passed a // namespace prefix and returns the URL. function(prefix) { return namespaces[prefix]; }); } else { // Otherwise, we assume for now that we're in IE and convert the // namespaces object into the textual form that IE requires. this.namespaceString = ""; if (namespaces != null) { for(var prefix in namespaces) { // Add a space if there is already something there if (this.namespaceString) this.namespaceString += ' '; // And add the namespace this.namespaceString += 'xmlns:' + prefix + '="' + namespaces[prefix] + '"'; } } } }; /** * This is the getNodes() method of XML.XPathExpression. It evaluates the * XPath expression in the specified context. The context argument should * be a Document or Element object. The return value is an array * or array-like object containing the nodes that match the expression. */ XML.XPathExpression.prototype.getNodes = function(context) { if (this.xpathExpr) { // If we are in a W3C-compliant browser, we compiled the // expression in the constructor. We now evaluate that compiled // expression in the specified context var result = this.xpathExpr.evaluate(context, // This is the result type we want XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); // Copy the results we get into an array. var a = new Array(result.snapshotLength); for(var i = 0; i < result.snapshotLength; i++) { a[i] = result.snapshotItem(i); } return a; } else { // If we are not in a W3C-compliant browser, attempt to evaluate // the expression using the IE API. try { // We need the Document object to specify namespaces var doc = context.ownerDocument; // If the context doesn't have ownerDocument, it is the Document if (doc == null) doc = context; // This is IE-specific magic to specify prefix-to-URL mapping doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); // In IE, the context must be an Element not a Document, // so if context is a document, use documentElement instead if (context == doc) context = doc.documentElement; // Now use the IE method selectNodes() to evaluate the expression return context.selectNodes(this.xpathText); } catch(e) { // If the IE API doesn't work, we just give up throw "XPath not supported by this browser."; } } } /** * This is the getNode() method of XML.XPathExpression. It evaluates the * XPath expression in the specified context and returns a single matching * node (or null if no node matches). If more than one node matches, * this method returns the first one in the document. * The implementation differs from getNodes() only in the return type. */ XML.XPathExpression.prototype.getNode = function(context) { if (this.xpathExpr) { var result = this.xpathExpr.evaluate(context, // We just want the first match XPathResult.FIRST_ORDERED_NODE_TYPE, null); return result.singleNodeValue; } else { try { var doc = context.ownerDocument; if (doc == null) doc = context; doc.setProperty("SelectionLanguage", "XPath"); doc.setProperty("SelectionNamespaces", this.namespaceString); if (context == doc) context = doc.documentElement; // In IE call selectSingleNode instead of selectNodes return context.selectSingleNode(this.xpathText); } catch(e) { throw "XPath not supported by this browser."; } } }; // A utility to create an XML.XPathExpression and call getNodes() on it XML.getNodes = function(context, xpathExpr, namespaces) { return (new XML.XPathExpression(xpathExpr, namespaces)).getNodes(context); }; // A utility to create an XML.XPathExpression and call getNode() on it XML.getNode = function(context, xpathExpr, namespaces) { return (new XML.XPathExpression(xpathExpr, namespaces)).getNode(context); };
<?xml version="1.0" encoding="ISO-8859-1"?> <contacts> <contact name="Able Baker"><email>able@example.com</email></contact> <contact name="Careful Dodger"><email>dodger@example.com</email></contact> <contact name="Eager Framer" personal="true"><email>framer@example.com</email></contact> </contacts>
var xmldoc = XML.load('addresses.xml'); var query = 'contacts/contact[@personal="true"]'; var serializer = new XMLSerializer();serializer.serializeToString(XML.getNode(xmldoc,query)) [6]
This talk available at http://jmvidal.cse.sc.edu/talks/javascriptxml/
Copyright © 2009 José M. Vidal
.
All rights reserved.
28 February 2007, 02:14PM