aide's Blog

April 22, 2009
Introduction

The XmlTextReader class is not the most intuitive class to work with, as the methods and properties are very low level. While the XmlTextReader class is rich in properties and methods, I've found that most of what it provides isn't necessary for the average day-to-day job. So, in this article, I'm going to present a moderately thin wrapper class for the XmlTextReader, which should be a helpful guide to using the XmlTextReader for programmers not familiar with this class. This article is also an introduction to a variety of other disciplines that I feel a beginner should be aware of--code commenting, abstraction and architecture, and unit tests. So, hopefully, there's something here for everybody!

Why Use an XmlReader?

To summarize from this site:

  • Use XmlTextReader if you need performance without schema validation or XPath/XSLT services.
  • Use XmlDocument if you need XPath services or need to update the XML.

Naturally, XmlTextReader is closer to the XML. It is a forward only reader, meaning that you can't go backwards. Contrast this with the XmlDocument class, which pulls in the entire document and allows you to random-access the XML tree. The XmlTextReader supports streams, and therefore should reduce memory requirements for very large documents.

Another advantage of the XmlTextReader is that it provides line and character position information, which can be very useful diagnostic information when there's a problem with the XML.

What Features Do I Want to Support?

There's a core set of features in XML that I want my reader to support:

  • XML declarations
  • Elements
  • Attributes
  • Namespaces
  • Element prefixes (both global and local)
  • Attribute prefixes
  • CDATA blocks
  • Inner text
  • Processing instructions
  • Node graphs (element children)

There are other features of XML, but these are the most common ones, and the ones I want to start with. The link cited above demonstrates a somewhat different approach than I am doing here, and it's useful to briefly discuss the difference. In the SoftArtisans link, many of the code snippets demonstrate looking for and evaluating specific elements and attributes of the XML, including optional ones. In other words, the application has expectations regarding the XML graph and content. The reader that I am presenting is tailored more to processing ad hoc XML, where there are no expectations regarding the graph and the content. Both approaches have there value depending on what you need to get accomplished.

The Unit Tests

The unit tests are written for my Advanced Unit Test application, downloadable here. The reason I'm using my unit test application instead of NUnit is because I want to take advantage of AUT's ability to execute tests in sequence, as I read through the XML. Yes, I could have instead written an XML fragment for each unit test, but I find this more convenient and more realistic, as I can work with the entire XML document.

The XML Test Document

Here's the XML test document, which illustrates each of the features described above:

 Collapse
<?xml version="1.0" encoding="utf-8"?> <RootNode AnAttribute="AttributeValue" xmlns:foo="Some namespace"> <ChildNode Attr1="1" Attr2="2" Attr3="3"/> <bar:Item xmlns:bar="LocalBar"/> <AttributeNamespace foo:MyAttribute="10"/> <![CDATA[some stuff]]> <!-- My comment --> <Element>Text</Element> <?do homework?> <ChildNode> <GrandchildNode Depth="3"/> </ChildNode> </RootNode>The Reader Architecture

Something this simple doesn't need an architecture, does it? In fact, it does. Even with something this simple, it's a good idea to consider what abstraction you might want (planning for the future) and helper objects that will make understanding and working with the code easier. And of course, we need to consider what kind of exceptions the reader will throw. As a side comment, it always surprises me how a good architecture, even for the simplest of functionality, practically eliminates monolithic code and helps to create nice small methods that are easily unit tested.

The IReaderInterface

I potentially want to read formats other than XML, while staying within the constraints of an XML-ish structure. For example, a comma separated value file (CSV) is a good candidate for an alternative reader implementation. By abstracting the reader, I can support alternative formats without having to change the code that uses the reader. This is a design decision that is best made early on.

The reader implements an IReader interface that provides the necessary abstraction layer:

 Collapse
/// <summary> /// Defines methods and attributes that a reader must implement. /// An interpreter interfaces with the reader to read the the /// elements, attributes, and other aspects of, typically, the /// xml. By implementing a custom reader, you can interpret other /// formats, however, note that the NodeType is an XmlNodeType, /// so even if you were to implement, say, a CSV reader, you would /// need to map your node type to an XmlNodeType. /// </summary> public interface IReader { /// <summary> /// If true, end elements are skipped during ReadNode. /// </summary> bool IgnoreEndElements { get; set;} /// <summary> /// Returns the number of attributes in the current element. /// </summary> int AttributeCount { get;} /// <summary> /// Returns the current depth of the element. Depth is a strange thing, /// as the element will be at depth n, but element attributes are at /// depth n+1. The root element is at depth 0. /// </summary> int Depth { get;} /// <summary> /// Thin wrapper for the underlying Value property, returns the CDATA text. /// </summary> string CData { get;} /// <summary> /// Thin wrapper for the underlying Value property, returns the comment text. /// The comment text is returned trimmed of leading and trailing whitespace. /// </summary> string Comment { get;} /// <summary> /// Thin wrapper for the underlying Value property, returns the element text. /// </summary> string Text { get;} /// <summary> /// Returns the line number and line position for the current reader position. /// </summary> LineInfo CurrentLineInfo { get;} /// <summary> /// Returns the element prefix, name, and current reader position. /// Unlike the XmlTextReader, the Name portion has any prefix stripped off. /// </summary> ElementTagInfo Element { get;} /// <summary> /// Returns the attribute prefix, name, value, and current reader position. /// Unlike the XmlTextReader, the Name portion has any prefix stripped off. /// </summary> AttributeTagInfo Attribute { get;} /// <summary> /// Returns a wrapper instance containing the processing instruction name and value. /// </summary> ProcessingInstructionInfo Instruction { get;} /// <summary> /// Returns the node type for the node at the current reader position. /// </summary> XmlNodeType NodeType { get;} /// <summary> /// Read the next node, optionally skipping end elements. /// </summary> XmlNodeType ReadNode(); /// <summary> /// Reads the first attribute associated with the current element. /// </summary> /// <returns>Returns null if no first attribute exists.</returns> AttributeTagInfo ReadFirstAttribute(); /// <summary> /// Reads the next element associated with the current element. /// </summary> /// <returns>Returns null if attempting to read past the last attribute.</returns> AttributeTagInfo ReadNextAttribute(); /// <summary> /// Smart attribute reader, reading either the first attribute /// or the next attribute depending on the reader state. /// </summary> /// <returns>Returns null if no further attributes exist.</returns> AttributeTagInfo ReadAttribute(); }

Since this is a beginning article, I want to emphasize something here--there is no excuse for not putting in at least basic comments in your code. None. It is a discipline that I myself have worked hard to achieve, but if you're writing a professional application that you or others may one day need to maintain, you simply have to force yourself to become disciplined about writing comments.

The interface:

  • Abstracts the reading of nodes and attributes.
  • Defines the methods and properties that make it clearer as to what is being read, rather than using the XmlTextReader's Text and Value properties

Anyone interested in implementing a custom reader now knows what the custom reader needs to implement. An application needing a reader can now reference the reader via the IReader interface, and a factory pattern can be used to instantiate the appropriate reader.

The Container Classes

There are several container classes that help encapsulate information relevant to all nodes and relevant to specific nodes. Creating classes that encapsulate fields improves code readability and provides a layer of separation from the underlying implementation (the Reader class, in this case). And no, none of the container classes are unit tested--you have to draw the line somewhere, and these classes are much too simple to spend the time on unit testing.

LineInfo

All XML nodes have line and character position information, which is encapsulated in the LineInfo class:

 Collapse
/// <summary> /// A wrapper class for the node line information. /// </summary> public class LineInfo { protected int lineNumber; protected int linePosition; /// <summary> /// Gets the line position. /// </summary> public int LinePosition { get { return linePosition; } } /// <summary> /// Gets the line number. /// </summary> public int LineNumber { get { return lineNumber; } } /// <summary> /// Constructor, requiring line number and position. /// </summary> public LineInfo(int lineNumber, int linePosition) { this.lineNumber = lineNumber; this.linePosition = linePosition; } }

Since this class is instantiated strictly by the reader, the properties are read-only.

NodeInfo

NodeInfo is an abstract class that encapsulates the two common elements of just about every XML node (there are a few exceptions): the node name and the node prefix.

 Collapse
/// <summary> /// Implements a wrapper for the information relevant to a node: /// the node line info, name and the node prefix. /// </summary> public abstract class NodeInfo { protected string name; protected string prefix; protected LineInfo lineInfo; /// <summary> /// Gets the LineInfo /// </summary> public LineInfo LineInfo { get { return lineInfo; } } /// <summary> /// Gets the prefix. /// </summary> public string Prefix { get { return prefix; } } /// <summary> /// Gets the name. /// </summary> public string Name { get { return name; } } /// <summary> /// Constructor. /// </summary> /// <param name="lineInfo">The LineInfo for the tag.</param> /// <param name="prefix">The tag prefix.</param> /// <param name="name">The tag name.</param> public NodeInfo(LineInfo lineInfo, string prefix, string name) { this.lineInfo = lineInfo; this.prefix = prefix; this.name = name; } }

It's an abstract class because we want to make sure that the implementation utilizes an appropriate concrete class derived from NodeInfo. The concrete implementation improves readability (since it qualifies the type of node information), and usually provides additional fields specific to the node type.

ElementNodeInfo

This class is a concrete implementation of NodeInfo, and adds a local namespace field, as elements can have local namespaces:

 Collapse
/// <summary> /// A concrete implementation for managing xml element nodes. This class adds a local /// namespace property. /// </summary> public class ElementNodeInfo : NodeInfo { protected string localNamespace; /// <summary> /// Gets the localNamespace. /// </summary> public string LocalNamespace { get { return localNamespace; } } public ElementNodeInfo(LineInfo lineInfo, string prefix, string name, string namespaceUri) : base(lineInfo, prefix, name) { localNamespace = namespaceUri; } }AttributeNodeInfo

This class is a concrete implementation of NodeInfo, and adds a value field, as attributes have values:

 Collapse
/// <summary> /// Implements a concrete attribute tag class, that adds a /// Value property for the attribute. /// </summary> public class AttributeNodeInfo : NodeInfo { protected string val; /// <summary> /// Gets the attribute value. /// </summary> public string Value { get { return val; } } public AttributeNodeInfo(LineInfo lineInfo, string prefix, string name, string val) : base(lineInfo, prefix, name) { this.val = val; } }ProcessingInstructionInfo

This class derives from AttributeNodeInfo. A processing instruction has a name and a value, like an attribute, but I've implemented a separate class to represent the concept of a processing instruction, even though it does not extend the AttributeNodeInfo class. This is merely a code readability decision.

 Collapse
/// <summary> /// A placeholder for the processing instruction. /// </summary> public class ProcessingInstructionInfo : AttributeNodeInfo { public ProcessingInstructionInfo(LineInfo lineInfo, string name, string value) : base(lineInfo, String.Empty, name, value) { } }The XmlTextReader

Instead of talking about the XmlTextReader as a class and its methods, which you can easily read about yourself, I'm going to show you the XmlTextReaderwithin the context of my Reader wrapper. This way, instead of just looking at documentation, you'll see the XmlTextReader in actual code, and I'll explain what I'm doing in the code and why.

Creating an XmlTextReader

Quite literally, the first stumbling block is in creating an XmlTextReader. It sounds simple, but according to Microsoft:

In the Microsoft .NET Framework version 2.0 release, the recommended practice is to create XmlReader instances using the Create method. This allows you to take full advantage of the new features introduced in this release.

Second, I want to control some aspects of the reading process, specifically, I almost always want to ignore whitespace. The default XmlTextReader returns all whitespace. So, to properly construct an XmlTextReader using Microsoft's recommended method and to have the ability to set some options, we have to do something like this:

 Collapse
/// <summary> /// Constructor. This initializes an XmlReader that wraps the XmlTextReader and passes /// in the setting to ignore whitespace (but not comments). /// </summary> /// <param name="xml">The xml to interpret.</param> public Reader(string xml) { StringReader textStream = new StringReader(xml); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreComments = false; settings.IgnoreWhitespace = true; xtr = new XmlTextReader(textStream); reader = XmlReader.Create(xtr, settings); firstAttribute = true; }

Before I go further, this constructor is the one I use for the unit tests, and it takes an XML string. You might instead want a constructor that takes a stream, and as you can see in the first line, I create a StringReader stream.

The second line creates an XmlReaderSettings instance, and I explicitly (just to show you another useful property) choose not to ignore comments, but I do want to ignore whitespace. Next, I create the XmlTextReader from the stream. But that's not enough. I now have to create an XmlReader, passing in theXmlTextReader and the desired settings. Now, we have properly constructed a reader, complying with Microsoft's guidelines, and having the ability to configure the reader to ignore whitespace.

If you're wondering about the last line, we'll get to that later.

The Constructor Unit Test
 Collapse
/// <summary> /// Verifies that no errors occur during construction /// and reader is position on nothing. /// </summary> [Test, Sequence(0)] public void ConstructorTest() { reader = new Reader(UnitTestResources.ReaderTest); reader.IgnoreEndElements = true; Assertion.Assert(reader.NodeType == XmlNodeType.None, "Expected 'None' for the node type."); }

The constructor reveals the fact that the XmlTextReader does not position itself on a valid node immediately after construction, as the NodeType is "None".

Reading the XML Declaration

Reading the XML declaration, as with all other elements, requires calling ReadNode:

 Collapse
/// <summary> /// Read the next node, optionally skipping end elements. /// </summary> public XmlNodeType ReadNode() { do { reader.Read(); } while (ignoreEndElements && (NodeType == XmlNodeType.EndElement)); firstAttribute = true; return reader.NodeType; }

My wrapper for the reader optionally skips end elements. If you don't do this, the reader will return EndElement node types, which, depending on what you are doing with the XML, may be superfluous. In the unit test constructor, this flag is set to true.

The XML Declaration Unit Test
 Collapse
/// <summary> /// Validates reading the xml declaration. /// </summary> [Test, Sequence(1)] public void XmlDeclarationTest() { reader.ReadNode(); // Reads the xml declaration. Assertion.Assert(reader.NodeType == XmlNodeType.XmlDeclaration, "Expected xml declaration node type."); Assertion.Assert(reader.AttributeCount==2, "Expected 2 attributes."); AttributeNodeInfo ati1 = reader.ReadFirstAttribute(); AttributeNodeInfo ati2 = reader.ReadNextAttribute(); Assertion.Assert(ati1.Name == "version", "Expected version attribute."); Assertion.Assert(ati1.Value == "1.0", "Expected version number."); Assertion.Assert(ati2.Name == "encoding", "Expected encoding attribute."); Assertion.Assert(ati2.Value == "utf-8", "Expected encoding value."); }

An XML declaration contains attributes just like an element node. I'll demonstrate the ReadFirstAttribute and ReadNextAttribute shortly.

Reading the Root Node and Other Elements

Immediately following the XML declaration should be the root node. My reader provides an Element property which returns an ElementNodeInfo instance that encapsulates the element name, prefix, and optional namespace. Looking at the implementation:

 Collapse
/// <summary> /// Returns the element prefix, name, and current reader position. /// Unlike the XmlTextReader, the Name portion has any prefix stripped off. /// </summary> public ElementNodeInfo Element { get { if (NodeType != XmlNodeType.Element) { throw new ReaderException("Not on an element node."); } ElementNodeInfo el = new ElementNodeInfo(CurrentLineInfo, reader.Prefix, NameWithoutPrefix, reader.NamespaceURI); return el; } }

You'll see that the ElementNodeInfo also consists of the reader's line and character position, and the element name is stripped of the prefix.

Reading the Root Node Unit Test

Reading an element node is straightforward, as the unit test demonstrates:

 Collapse
/// <summary> /// Validates reading the xml root node. /// </summary> [Test, Sequence(2)] public void RootNodeTest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.Element, "Expected element node type."); ElementNodeInfo eti = reader.Element; Assertion.Assert(eti.Name == "RootNode", "Expecte root node element."); Assertion.Assert(eti.Prefix == "", "Expected a blank prefix."); Assertion.Assert(reader.AttributeCount == 2, "Expected 2 attributes."); }

The ReadNode method is called to move past the XML declaration node and onto the root node. The unit test verifies that this happened correctly.

There's another element test later on, which tests that a local namespace has been correctly read:

 Collapse
/// <summary> /// Validates reading an element with a local namespace. /// </summary> [Test, Sequence(8)] public void LocalNamespaceTest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.Element, "Expected element node type."); ElementNodeInfo eti = reader.Element; Assertion.Assert(eti.Prefix == "bar", "Unexpected prefix."); Assertion.Assert(eti.LocalNamespace == "LocalBar", "Unexpected namespace."); }Reading Attributes

Most XML elements contain attributes, and the root node includes two attributes, one of which is an XML namespace declaration. The XmlTextReader provides two methods for reading an attribute, MoveToFirstAttribute and MoveToNextAttribute, which return a boolean true if successful, false otherwise. I've modified this implementation slightly:

 Collapse
/// <summary> /// Reads the first attribute associated with the current element. /// </summary> /// <returns>Returns null if no first attribute exists.</returns> public AttributeNodeInfo ReadFirstAttribute() { bool val = xtr.MoveToFirstAttribute(); AttributeNodeInfo ret = null; if (val) { ret = Attribute; firstAttribute = false; } return ret; }

and:

 Collapse
/// <summary> /// Reads the next attribute associated with the current element. /// </summary> /// <returns>Returns null if attempting to read past the last attribute.</returns> public AttributeNodeInfo ReadNextAttribute() { bool val=xtr.MoveToNextAttribute(); AttributeNodeInfo ret = null; if (val) { ret = Attribute; } return ret; }

Both of these methods return an AttributeNodeInfo instance, encapsulating the reader's line and character position and the attribute name, prefix, and value. A null is returned if there are no further attributes to read. You can use these methods, or you can use another method that avoids having to figure out whether to call ReadFirstAttribute or ReadNextAttribute. My reader figures this out automatically for you, and here's where the firstAttributeboolean comes into play:

 Collapse
/// <summary> /// Smart attribute reader, reading either the first attribute /// or the next attribute depending on the reader state. /// </summary> /// <returns>Returns null if no further attributes exist.</returns> public AttributeNodeInfo ReadAttribute() { AttributeNodeInfo ret = null; if (firstAttribute) { ret = ReadFirstAttribute(); } else { ret = ReadNextAttribute(); } return ret; }

The firstAttribute flag is set whenever ReadNode is called. It's cleared when the first attribute is read, either by calling ReadFirstAttribute orReadAttribute.

The Attribute Unit Tests

The following sequence of unit tests test the first, next, and "smart" attribute reader:

 Collapse
/// <summary> /// Validate reading the first attribute. /// </summary> [Test, Sequence(3)] public void ReadFirstAttributeTest() { AttributeNodeInfo ati = reader.ReadFirstAttribute(); Assertion.Assert(ati.Name == "AnAttribute", "Unexpected first attribute name."); Assertion.Assert(ati.Value=="AttributeValue", "Unexpected first attribute value."); } /// <summary> /// Validate reading the second attribute. /// </summary> [Test, Sequence(4)] public void ReadNextAttributeTest() { AttributeNodeInfo ati = reader.ReadNextAttribute(); // Note that we are stripping off the prefix from the name! Assertion.Assert(ati.Name == "foo", "Unexpected second attribute name."); Assertion.Assert(ati.Prefix == "xmlns", "Unexpected second attribute prefix."); Assertion.Assert(ati.Value == "Some namespace", "Unexpected second attribute value."); } /// <summary> /// Verify that a null is returned attempting to read past the last attribute. /// </summary> [Test, Sequence(5)] public void NoFurtherAttributeTest() { AttributeNodeInfo ati=reader.ReadNextAttribute(); Assertion.Assert(ati == null, "Expected a null after the last attribute."); } /// <summary> /// Verify reading the next element. /// </summary> [Test, Sequence(6)] public void ReadNextElement() { reader.ReadNode(); ElementNodeInfo eti = reader.Element; Assertion.Assert(eti.Name == "ChildNode", "Unexpected element."); Assertion.Assert(reader.Depth == 1, "Unexpected depth."); } /// <summary> /// Test the smart attribute reader implementation, which automatically determines /// whether to call ReadFirstAttribute or ReadNextAttribute. /// </summary> [Test, Sequence(7)] public void SmartAttributeReaderTest() { int i = 0; while (reader.ReadAttribute() != null) { ++i; } Assertion.Assert(i == 3, "Expected 3 attributes."); } /// <summary> /// Validates reading an attribute with a prefix. /// </summary> [Test, Sequence(9)] public void AttributePrefixTest() { reader.ReadNode(); AttributeNodeInfo ati=reader.ReadAttribute(); Assertion.Assert(ati.Prefix == "foo", "Unexpected prefix."); Assertion.Assert(ati.Name == "MyAttribute", "Unexpected attribute."); Assertion.Assert(ati.Value == "10", "Unexpected value."); }Reading CDATA

A CDATA block lets you include freeform text in the XML, such as code. My reader provides a CData property which returns the CDATA text as a string:

 Collapse
/// <summary> /// Thin wrapper for the underlying Value property, returns the CDATA text. /// </summary> public string CData { get { if (NodeType != XmlNodeType.CDATA) { throw new ReaderException("Not on a CDATA node."); } return reader.Value; } }

As you can see, the CData property validates the node type that wraps the Value property.

The CDATA Unit Test
 Collapse
/// <summary> /// Validates reading a CDATA block. /// </summary> [Test, Sequence(10)] public void CDATATest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.CDATA, "Expected CDATA node."); Assertion.Assert(reader.CData == "some stuff", "Unexpected CDATA text."); }Reading Comments

Reading XML comments is just like getting the CDATA text. Once we know that the node is a comment node, we return the Value property which contains the comment text. The reader also trims any leading and trailing whitespace, which is often used to make the XML comments more readable.

 Collapse
/// <summary> /// Thin wrapper for the underlying Value property, returns the comment text. /// The comment text is returned trimmed of leading and trailing whitespace. /// </summary> public string Comment { get { if (NodeType != XmlNodeType.Comment) { throw new ReaderException("Not on a comment node."); } return reader.Value.Trim(); } }The Comment Unit Test
 Collapse
/// <summary> /// Validates reading a comment block. /// </summary> [Test, Sequence(11)] public void CommentTest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.Comment, "Expected comment node."); Assertion.Assert(reader.Comment == "My comment", "Unexpected comment text."); }Reading Inner Element Text

As the XmlTextReader moves through the XML, any inner text is its own Text node type. The reader's Text property is a thin wrapper for theXmlTextReader's Value property:

 Collapse
/// <summary> /// Thin wrapper for the underlying Value property, returns the element text. /// </summary> public string Text { get { if (NodeType != XmlNodeType.Text) { throw new ReaderException("Not on a text node."); } return reader.Value; } }The Text Unit Test
 Collapse
/// <summary> /// Validates reading inner element text. /// </summary> [Test, Sequence(12)] public void TextTest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.Element, "Expected element."); reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.Text, "Expected text node."); Assertion.Assert(reader.Text == "Text", "Unexpected text value."); }Reading Process Instructions

Process instructions are another kind of XML nodes. These may contain useful meta-instructions for the engine that is processing the XML. The reader provides a thin wrapper for getting the process instruction:

 Collapse
/// <summary> /// Returns a wrapper instance containing the processing instruction name and value. /// </summary> public ProcessingInstructionInfo Instruction { get { if (NodeType != XmlNodeType.ProcessingInstruction) { throw new ReaderException("Not on a processing instruction node."); } ProcessingInstructionInfo proc = new ProcessingInstructionInfo(CurrentLineInfo, reader.Name, reader.Value); return proc; } }Process Instruction Unit Test
 Collapse
/// <summary> /// Validates reading a processing instruction. /// </summary> [Test, Sequence(13)] public void ReadProcessingInstructionTest() { reader.ReadNode(); Assertion.Assert(reader.NodeType == XmlNodeType.ProcessingInstruction, "Expected processing instruction."); ProcessingInstructionInfo pii = reader.Instruction; Assertion.Assert(pii.Name == "do", "Unexpected name."); Assertion.Assert(pii.Value == "homework", "Unexpected value."); }Working with the XML Graph

Lastly, one of the important things about XML is that it is hierarchical. The reader provides a thin wrapper to the XmlTextReader's Depth property (a very thin wrapper):

 Collapse
/// <summary> /// Returns the current depth of the element. Depth is a strange thing, /// as the element will be at depth n, but element attributes are at /// depth n+1. The root element is at depth 0. /// </summary> public int Depth { get { return reader.Depth; } }

The point being though that we need this property implemented by any class that realizes IReader.

The Depth Unit Test
 Collapse
/// <summary> /// Validates node depth. Note how the third ReadNode returns a depth of 0, /// as this is the end of the xml. The root node is at depth 0, as soon as /// the reader is positioned on an attribute of a node or a child element, /// the depth is incremented. /// </summary> [Test, Sequence(14)] public void DepthTests() { reader.ReadNode(); // Reads the ChildNode element. Assertion.Assert(reader.Depth == 1, "Depth should be 1."); reader.ReadNode(); // Reads the GranchildNode element. Assertion.Assert(reader.Depth == 2, "Depth should be 2."); reader.ReadAttribute(); // Reads the Depth attribute. Assertion.Assert(reader.Depth == 3, "Depth should be 3."); reader.ReadNode(); // Reads to end. Assertion.Assert(reader.Depth == 0, "Depth should be 0."); }

This unit test reveals one of the side-effects of ignoring the XML end element node type, which is that the depth can pop several levels. This should be taken into consideration when writing an application that actually does something with the XML.

 

About the Author

Marc Clifton

Occupation:Architect
Company:Interacx
Location:United States United States

sb
April 19, 2009
Introduction

When my company asked me to work on this article for the client, I got a chance to work with JAXB concepts. I wanted to share my knowledge with you guys so that this will be helpful to me and people who are working on Java XML concepts.

Overview

eXtensible Markup Language (XML) is a platform and language-independent way of defining tags. XML allows you to use meaningful tags to represent data in a structured format. Unlike HyperText Markup Language (HTML), which is used to display text, XML is a language to create extensible custom tags to represent the structure of data.

SAX parser is an event driven low-level parser, that responds to the elements of an XML document as it parses through the documents. The data is not maintained in memory. Efficiency of parsing data into elements is the key feature of SAX parser. DOM parser is a high-level parser that maintains the data structures of a document in memory as it parses through the document. This helps you to manage and manipulate data as needed. DOM API follows the tree model for maintaining the data in memory.

Formerly known as Project Adelard, Java Architecture for XML binding (JAXB) combines the benefits of Document Object Model (DOM) parser and Simple API for XML (SAX) parser.

JAXB reduces the execution time significantly and creates a robust object model for enterprise level applications.

This reference point explains how to use JAXB to create and distribute high-performance XML-enabled applications with minimum effort.

Overview of XML

This table describes the important components used in XML:

ComponentDescription
Element tagsUsed to describe elements
Processing InstructionsSpecial instructions to the XML processor
Document Type Declarations (DTD)Used to carry out structure bound data modeling
Entity referencesUsed to represent the aliases of an entity data
CommentsUsed to identify and highlight the importance of a specific function/procedure in an XML document. Similar to other conventional packages, XML processors and parsers do not consider comments while compiling
Marked SectionsThe data in an XML document, which are marked, will not be processed or parsed by XML applications, although the data is valid for parsing and processing XML documents.

XML parsers are used to check whether XML documents are well formed or not. In addition, they are used to convert XML nodes into Java objects or elements. There are two types of parsers: validating and non-validating. Validating parsers verify that the XML document conforms to a DTD or a schema.

A Java application that uses XML technologies needs to parse the data objects of XML. The parsing is done based on the schemas and DTDs that are defined for that particular document. You can use various technologies to parse an XML document into Java objects. Some of which are SAX, DOM and JAXB.

Introducing JAXB

You can use JAXB API to map XML documents to Java objects. You can use JAXB API and tools to marshal or convert XML contents to Java objects. You can access and validate the Java objects against a schema. In addition, you can use JAXB API to un-marshal or convert Java objects into an XML document.

Advantages of JAXB

JAXB provides a layer of abstraction between XML documents and Java applications. This helps you develop enterprise applications. JAXB applications can match the speed of SAX by using the binding mechanism, which maintains information in the memory.

In addition, JAXB can convert data in XML elements into equivalent valid Java objects and set constraints with the help of XML schemas or DTDs.

JAXB frees you from writing and debugging the XML parsing codes. With generated conversion codes, you can write the applications that can access the XML documents through normal Java data interfaces.

You can extend the functionalities for the generated class codes. In Java applications, you may want to have control over the XML schema components through the Java objects. For this, you can customize the binding schema for the different needs.

Because of the object orientation, JAXB based applications are helpful to access multiple XML documents.

Comparison of JAXB and SAX

The difference between JAXB and SAX are:

  • SAX is an event driven model, whereas JAXB is based on binding of Java objects with XML elements.
  • Data storage capability is higher in JAXB compared to SAX.
  • Pre-complied Java classes and predefined schema logic enables JAXB parser to avoid dynamic interpretation, enhancing its efficiency compared to SAX parser.
Comparison of JAXB with DOM

Although both JAXB and DOM have data storage capabilities, JAXB applications are specific to a single schema, whereas DOM applications can be managed with multiple schemas. JAXB applications are faster than DOM applications.

Note:

Since JAXB applications are specific to a single schema, they can utilize memory more efficiently in comparison to DOM applications.

Architecture of JAXB

The basic components required for XML data binding are:

  • Binding Compiler: Transforms or binds the DTDs or Schemas with Java objects.
  • Runtime Binding Framework: An API used for supporting the basic operations such as marshaling, un-marshaling, and validation of Java classes.
    • Marshaling: The process of generating Java objects for a given XML document.
    • Un-marshaling: The process of generating XML documents from Java objects.
    • Validation: The process of identifying the desired Java object based on DTD/Schema.
  • Binding Language: Any language that supports XML, such as DTD, can be used as binding language. This language describes the binding of DTDs or Source Schema with a Java representation. The declarations are intended to generate Java packages, classes, or interfaces.

JAXB Architecture

Java representation of JAXB architecture

Complex data contents defined by using DTD or Schema in an XML document are bound to the content interfaces, which are generated by a JAXB compiler. Simple contents such as attributes and elements of an XML node are directly bound to the properties of the content interfaces and can be accessed through setter and getter methods. Using properties, you can reference two interfaces at the same time. You can effectively use the generated classes as both content interfaces and implementation interfaces to extend the functionality, which makes JAXB architecture more flexible and competent.

Binding Schema/DTD to Java classes

Binding Framework API helps you to compile XML Schema and Java classes for marshalling and un-marshalling of Java objects.

Binding Derived Classes

When you bind DTD with a binding schema:

  • Course-grained schema components, such as element-type definitions, are bound to a content class.
  • Fine-grained components, such as attribute declarations, are bound directly to a property within a content class.
  • A property is realized by a set of access methods.
  • The methods include the standard get and set events to retrieve and modify a property value. You can also delete and re-initialize a property value.

You can use:

  • Schema compiler to bind DTD with a binding schema and generate Java classes and interfaces.
  • Source schema language such as DTD to write source schema.
  • The binding language to write binding schema.
Note

If you do not mention the attribute types for components in the binding schema, the schema compiler uses the default String data type.

Validations on XML Schema and Binding Objects

You have to validate a binding object against three constraints:

  • Type constraint: Imposes requirements of values that may be given as an attribute to an XML document or content of a #PCDATA-only elements.
  • Local structural constraint: Imposes requirements on every instance of a specific element type.
  • Global structural constraint: Imposes requirements on the entire document.
Static Schema Constraint Enforcement

The Java programming language ensures that a schema constraint is checked at compile time and dynamically generates the available methods for the attribute mentioned in the schema. For example, if you have a schema constraint attribute by the name String, the derived methods will be:

 Collapse
public void setName (String name); public String getName ();Simple Dynamic Schema Constraint Enforcement

The enforcement performs a run-time check and throws an exception on failure. This is best suited for type constraints that do not map directly to the Java classes or primitives.

For example, if an attribute is constrained to an integer value between 0 and 100, the set method can possibly throw a run-time exception when the value passed to the method is out of range.

Complex Dynamic Schema Constraint Enforcement

The enforcement performs a check at run-time and throws an exception on failure.

  • Local structural constraint checks whether or not the types of complex type's children match the schema's content model.
  • Global structural constraint examines the entire content tree to check for uniformity of ID values and check if every IDREF has a corresponding ID.

The steps that you need to follow before working on JAXB generated classes are:

  1. Install JAXB software
  2. Write a binding schema, which contains instructions on how to bind DTD to classes.
  3. Execute the schema compiler with the DTD and binding schema as input to the complier and generate the source code.
  4. Compile the source code to generate the classes.
About the Author
Occupation:Web Developer
Location:India India
sb
March 29, 2009
Introduction

The Extensible Markup Language (XML) is a general-purpose markup language. It is classified as an extensible language because it allows its users to define their own tags. In Software Engineering, extensible refers to the system that can be modified by changing or adding features. Its primary purpose is to facilitate the sharing of data across different information systems, particularly via the Internet.

XML is recommended by the World Wide Web Consortium (W3C). It is a fee-free open standard. The W3C recommendation specifies both the lexical grammar, and the requirements for parsing.

The basic difference between HTML and XML is: 

  • HTML was designed to display data and to focus on how data looks
  • XML is designed to describe data and to focus on what data is
A Simple Program using XML
 Collapse
<?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <!-- Sample Program --> <Note> <to>Irshad</to> <from>Farhan</from> <heading>Test Application</heading> <body>Don't forget me this weekend!</body> </Note>Note

A well formed XML must have proper opening and closing tags.

Data can be stored in child elements or in attributes, e.g.:

 Collapse
<Note to=&quot;Irshad&quot;> //XML attribute <from>Farhan</from> //XML child element <heading>Test Application</heading> <body>Don't forget me this weekend!</body> </Note>

Attributes are handy in HTML, but in XML, it is better to avoid them. Use child elements if the information feels like data.

XML Validation

There are two levels of correctness of an XML document:

  1. XML with correct syntax is Well Formed XML
  2. XML validated against a DTD is Valid XML

A Well Formed XML document is a document that conforms to the XML syntax rules like:

  • XML documents must have a root element
  • XML elements must have a closing tag 
  • XML tags are case sensitive 
  • XML elements must be properly nested 
  • XML attribute values must always be quoted 

A Valid XML document is a "Well Formed" XML document, which conforms to the rules of a Document Type Definition (DTD).

Document Type Definition (DTD)

The purpose of a DTD is to define the legal building blocks of an XML document. It defines the document structure with a list of legal elements.

A DTD can be declared inline inside an XML document, or as an external reference.

 Collapse
Internal DTD Declaration:

If the DTD is declared inside the XML file, it should be wrapped in a DOCTYPE definition with the following syntax:

 Collapse
<?xml version=&quot;1.0&quot;?> <!DOCTYPE Note [ <!ELEMENT Note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> ]>

The DTD above is interpreted like this:

  • !DOCTYPE Note defines that the root element of this document is Note
  • !ELEMENT Note defines that the note element contains four elements: "to,from,heading,body"
  • !ELEMENT to defines the to element to be of the type #PCDATA
  • !ELEMENT from defines the from element to be of the type #PCDATA, etc.
 Collapse
External DTD Declaration:

If the DTD is declared in an external file, it should be wrapped in a DOCTYPE definition with the following syntax:

 Collapse
<?xml version=&quot;1.0&quot;?> <!DOCTYPE note SYSTEM &quot;note.dtd&quot;> <note> <to>Irshad</to> <from>Farhan</from> <heading>Test Application</heading> <body>Don't forget me this weekend!</body> </note>

And this is the file note.dtd which contains the DTD:

 Collapse
<!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> Reference XML Schema

XML Schema is used to define the legal building blocks of an XML document, just like a DTD. XML Schemas are the successors of DTDs and also referred to as XML Schema Definition (XSD).

XML Schemas are now used in most Web applications as a replacement for DTDs and in the near future, they will completely replace DTDs due to the following reasons:

  • XML Schemas are extensible to future additions
  • XML Schemas are richer and more powerful than DTDs
  • XML Schemas are written in XML
  • XML Schemas support data types
  • XML Schemas support namespaces
Example

An example of a very simple XML Schema Definition to describe a country is given below:

 Collapse
<xs:schema xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;> <xs:element name=&quot;country&quot; type=&quot;Country&quot;/> <xs:complexType name=&quot;Country&quot;> <xs:sequence> <xs:element name=&quot;name&quot; type=&quot;xs:string&quot;/> <xs:element name=&quot;population&quot; type=&quot;xs:decimal&quot;/> </xs:sequence> </xs:complexType> </xs:schema>

An example of an XML document that confirms to this schema is given below (assuming the schema file name is country.xsdand both files are in the same directory):

 Collapse
<country> xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;country.xsd&quot;>XQuery

The best way to explain XQuery is to say that:

"XQuery is to XML what SQL is to database tables"

XQuery was designed to query XML data. XQuery is also known as XML Query.

The mission of the XML Query project is to provide flexible query facilities to extract data from real and virtual documents on the World Wide Web, therefore finally providing the needed interaction between the Web world and the database world. Ultimately, collections of XML files will be accessed like databases.

XQuery uses XPath (XPath is a language for finding information in an XML document. XPath is used to navigate through elements and attributes in an XML document.) expression syntax to address specific parts of an XML document. It supplements this with a SQL-like "FLWOR expression" for performing joins. A FLWOR expression is constructed from the five clauses after which it is named: FOR, LET, WHERE, ORDER BY, RETURN.

Example

Let's take any XML document:

 Collapse
<?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?> <bookstore> <book category=&quot;Poetry&quot;> <title>Bang-e-Dara</title> <author>Allama Iqbal</author> <year>1930</year> <price>100.00</price> </book> <book category=&quot;Children&quot;> <title>Chocolate Factory</title> <author>Amra Alam</author> <year>2007</year> <price>50.00</price> </book> </bookstore>

A simple XQuery can be written to extract a record out of this XML document like:

 Collapse
&quot;doc(&quot;books.xml&quot;)/bookstore/book[price<70]&quot;

The XQuery above will extract the following:

 Collapse
<book category=&quot;Children&quot;> <title>Chocolate Factory</title> <author>Amra Alam</author> <year>2007</year> <price>50.00</price> </book>XML Validation Against XSD

XML document can be validated against XML schema (XSD). XSD checks the XML document's complete structure and reports an error if any datatype mismatches or node element does not exist.

Below is sample code written in C# which takes an XML document and an XSD document as input and validates the XML document:

 Collapse
using System.Xml; using System.Xml.Schema; public void validateXML() { strXMLFileName = Server.MapPath(&quot;XMLDoc.xml&quot;); strXSDFileName = Server.MapPath(&quot;GMACApplicationTypes.xsd&quot;); XmlTextReader tr = new XmlTextReader(strXMLFileName); XmlSchemaCollection sc = new XmlSchemaCollection(); XmlValidatingReader vr = new XmlValidatingReader(tr); try { sc.Add(null, strXSDFileName); vr.ValidationType = ValidationType.Schema; vr.Schemas.Add(sc); vr.ValidationEventHandler += ValidationCallBack; while ((vr.Read())) { } } catch (Exception ee) { Response.Write(ee.Message + &quot;:&quot; + ee.Message); } } public void ValidationCallBack(object sender, ValidationEventArgs args) { //textArea will contain all validation summary Summary.Text += &quot;\nValidation error:\n&quot;; Summary.Text += args.Exception.ToString(); error_count++; }
License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author
Farhan Ali
sb
March 29, 2009
ContentsEmbedding and including

Let's first see a simple example:

 Collapse
<html> <head> <title>This is a JavaScript example</title> <script language="JavaScript"> <!-- document.write("Hello World!"); //--> </script> </head> <body> Hi, man! </body> </html>

Usually, JavaScript code starts with the tag <script language="JavaScript"> and ends with the tag </script>. The code placed between <head> and </head>. Sometimes, people embed the code in the <body> tags:

 Collapse
<html> <head></head> <body> <script> .....// The code embedded in the <body> tags. </script> </body> </html>

Why do we place JavaScript code inside comment fields <!-- and //-->? It's for ensuring that the Script is not displayed by old browsers that do not support JavaScript. This is optional, but considered good practice. The LANGUAGE attribute also is optional, but recommended. You may specify a particular version of JavaScript:

 Collapse
<script language="JavaScript1.2">

You can use another attribute SRC to include an external file containing JavaScript code:

 Collapse
<script language="JavaScript" src="hello.js"></script>

For example, shown below is the code of the external file hello.js:

 Collapse
document.write("Hello World!")

The external file is simply a text file containing JavaScript code with the file name extension ".js". Note:

  1. Including an external file only functions reliably across platforms in the version 4 browsers.
  2. The code can't include tags <script language...> and </script>, or you will get an error message.

Back to top

write and writeln

In order to output text in JavaScript you must use write() or writeln(). Here's an example:

 Collapse
<HTML> <HEAD> <TITLE> Welcome to my site</TITLE></HEAD> <BODY> <SCRIPT LANGUAGE="JAVASCRIPT"> <!-- document.write("Welcome to my site!"); // --> </SCRIPT> </BODY> </HTML>

Note: the document object write is in lowercase as JavaScript is case sensitive. The difference between write andwriteln is: write just outputs a text, writeln outputs the text and a line break.

Back to top

Document object

The document object is one of the most important objects of JavaScript. Shown below is a very simple JavaScript code:

 Collapse
document.write("Hi there.")

In this code, document is the object. write is the method of this object. Let's have a look at some of the other methods that the document object possesses.

 

lastModifiedYou can always include the last update date on your page by using the following code:
 Collapse
<script language="JavaScript"> document.write("This page created by John N. Last update:" + document.lastModified); </script>

All you need to do here is use the lastModified property of the document. Notice that we used + to put together This page created by John N. Last update: and document.lastModified.

 

bgColor and fgColorLets try playing around with bgColor and fgColor:

 

 Collapse
<script> document.bgColor="black" document.fgColor="#336699" </script>

Back to top

Message Box

 

alertThere are three message boxes: alert, confirm, and prompt. Let's look at the first one:
 Collapse
<body> <script> window.alert("Welcome to my site!") </script> </body>

You can put whatever you want inside the quotation marks.

 

confirmAn example for confirm box:
 Collapse
window.confirm("Are you sure you want to quit?")

 

promptPrompt box is used to allow a user to enter something according the promotion:

 

 Collapse
window.prompt("please enter user name")

In all our examples above, we wrote the box methods as window.alert(). Actually, we could simply write the following instead as:

 Collapse
alert() confirm() prompt()

Back to top

Variables and Conditions

Let's see an example:

 Collapse
<script> var x=window.confirm("Are you sure you want to quit") if (x) window.alert("Thank you.") else window.alert("Good choice.") </script>

There are several concepts that we should know. First of all, var x= is a variable declaration. If you want to create a variable, you must declare the variable using the var statement. x will get the result, namely, true or false. Then we use a condition statement if else to give the script the ability to choose between two paths, depending on this result (condition for the following action). If the result is true (the user clicked "ok"), "Thank you" appears in the window box. If the result is false (the user clicked "cancel"), "Good choice" appears in the window box instead. So we can make more complex boxes using var, if and those basic methods.

 Collapse
<script> var y=window.prompt("please enter your name") window.alert(y) </script>

Another example:

 Collapse
<html><head> <script> var x=confirm("Are you sure you want to quit?") if (!x) window.location="http://www.yahoo.com" </script> </head> <body> Welcome to my website!. </body></html>

If you click "cancel", it will take you to yahoo, and clicking ok will continue with the loading of the current page "Welcome to my website!". Note:if (!x)means: if click "cancel". In JavaScript, the exclamation mark ! means: "none".

Back to top

Function

Functions are chunks of code.Let's create a simple function:

 Collapse
function test() { document.write("Hello can you see me?") }

Note that if only this were within your <script></script> tags, you will not see "Hello can you see me?" on your screen because functions are not executed by themselves until you call upon them. So we should do something:

 Collapse
function test() { document.write("Hello can you see me?") } test()

Last linetest() calls the function, now you will see the words "Hello can you see me?".

Back to top

Event handler

What are event handlers? They can be considered as triggers that execute JavaScript when something happens, such as click or move your mouse over a link, submit a form etc.

 

onClickonClick handlers execute something only when users click on buttons, links, etc. Let's see an example:

 

 Collapse
<script> function ss() { alert("Thank you!") } </script> <form> <input type="button" value="Click here" onclick="ss()"> </form>

The function ss() is invoked when the user clicks the button. Note: Event handlers are not added inside the <script>tags, but rather, inside the html tags.

 

onLoadThe onload event handler is used to call the execution of JavaScript after loading:

 

 Collapse
<body onload="ss()"> <frameset onload="ss()"> <img src="whatever.gif" onload="ss()">

 

onMouseover,onMouseoutThese handlers are used exclusively with links.

 

 Collapse
<a href="#" onMouseOver="document.write('Hi, nice to see you!">Over Here!</a> <a href="#" onMouseOut="alert('Good try!')">Get Out Here!</a>

 

onUnloadonunload executes JavaScript while someone leaves the page. For example to thank users.

 

 Collapse
<body onunload="alert('Thank you for visiting us. See you soon')">

 

Handle multiple actionsHow do you have an event handler call multiple functions/statements? That's simple. You just need to embed the functions inside the event handler as usual, but separate each of them using a semicolon:

 

 Collapse
<form> <input type="button" value="Click here!" onClick="alert('Thanks for visiting my site!');window.location='http://www.yahoo.com'"> </form>

Back to top

Form

Let's say you have a form like this:

 Collapse
<form name="aa"> <input type="text" size="10" value="" name="bb"><br> <input type="button" value="Click Here"onclick="alert(document.aa.bb.value)"> </form>

Notice that we gave the names to the form and the element. So JavaScript can gain access to them.

 

onBlurIf you want to get information from users and want to check each element (ie: user name, password, email) individually, and alert the user to correct the wrong input before moving on, you can use onBlur. Let's see how onblur works:

 

 Collapse
<html><head><script> function emailchk() { var x=document.feedback.email.value if (x.indexOf("@")==-1) { alert("It seems you entered an invalid email address.") document.feedback.email.focus() } } </script></head><body>
 Collapse
<form name="feedback"> Email:<input type="text" size="20" name="email" onblur="emailchk()"><br> Comment: <textarea name="comment" rows="2" cols="20"></textarea><br> <input type="submit" value="Submit"> </form> </body></html>

If you enter an email address without the @, you'll get an alert asking you to re-enter the data. What is:x.indexOf(@)==-1? This is a method that JavaScript can search every character within a string and look for what we want. If it finds it will return the position of the char within the string. If it doesn't, it will return -1. Therefore,x.indexOf("@")==-1 basically means: "if the string doesn't include @, then:

 Collapse
alert("It seems you entered an invalid email address.") document.feedback.email.focus()

What's focus()? This is a method of the text box, which basically forces the cursor to be at the specified text box.onsubmit Unlike onblur, onsubmit handler is inserted inside the <form> tag, and not inside any one element. Lets do an example:

 Collapse
<script> <!-- function validate() { if(document.login.userName.value=="") { alert ("Please enter User Name") return false } if(document.login.password.value=="") { alert ("Please enter Password") return false } } //--> </script>
 Collapse
<form name="login" onsubmit="return validate()"> <input type="text" size="20" name="userName"> <input type="text" size="20" name="password"> <input type="submit" name="submit" value="Submit"> </form>

Note:
if(document.login.userName.value==""). This means "If the box named userName of the form named login contains nothing, then...". return false. This is used to stop the form from submitting. By default, a form will return true if submitting. return validate() That means, "if submitting, then call the function validate()".

 

Protect a file by using LoginLet's try an example

 

 Collapse
<html><head> <SCRIPT Language="JavaScript"> function checkLogin(x) { if ((x.id.value != "Sam")||(x.pass.value !="Sam123")) { alert("Invalid Login"); return false; } else location="main.htm" } </script>
 Collapse
</head><body> <form> <p>UserID:<input type="text" name="id"></p> <p>Password:<input type="password" name="pass"></p> <p><input type="button" value="Login" onClick="checkLogin(this.form)"></p> </form> </body></html>

|| means "or", and ,!= indicates "not equal". So we can explain the script: "If the id does not equal 'Sam', or the password does not equal 'Sam123', then show an alert ('Invalid Login') and stop submitting. Else, open the page 'main.htm'".

Back to top

Link

In most cases, a form can be repaced by a link:

 Collapse
<a href="JavaScript:window.location.reload()">Click to reload!</a>

More examples:

 Collapse
<a href="#" onClick="alert('Hello, world!')">Click me to say Hello</a><br>
 Collapse
<a href="#" onMouseOver="location='main.htm'">Mouse over to see Main Page</a>

Back to top

Date

Let's see an example:

 Collapse
<HTML><HEAD><TITLE>Show Date</TITLE></HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> var x= new Date(); document.write (x); </SCRIPT> </BODY></HTML>

To activate a Date Object, you can do this: var x=new Date(). Whenever you want to create an instance of the date object, use this important word: new followed by the object name().

 

Dynamically display different pagesYou can display different pages according to the different time. Here is an example:

 

 Collapse
var banTime= new Date() var ss=banTime.getHours() if (ss<=12) document.write("<img src='banner1.gif'>") else document.write("<img src='banner2.gif'>") Date object
Methods
getDate 
getTime
getTimezoneOffset
getDay
getMonth
getYear
getSeconds
getMinutes
getHours

Back to top

Window

 

Open a windowTo open a window, simply use the method "window.open()":

 

 Collapse
<form> <input type="button" value="Click here to see" onclick="window.open('test.htm')"> </form>

You can replace test.htm with any URL, for example, with http://www.yahoo.com.

 

Size, toolbar, menubar, scrollbars, location, statusLet's add some of attributes to the above script to control the size of the window, and show: toolbar, scrollbars etc. The syntax to add attributes is:

 

 Collapse
open("URL","name","attributes")

For example:

 Collapse
<form> <input type="button" value="Click here to see" onclick="window.open('page2.htm','win1','width=200,height=200,menubar')"> </form>

Another example with no attributes turned on, except the size changed:

 Collapse
<form> <input type="button" value="Click here to see" onclick="window.open('page2.htm','win1','width=200,height=200')"> </form>

Here is the complete list of attributes you can add:

widthheighttoolbar
locationdirectoriesstatus
scrollbarsresizablemenubar

 

ReloadTo reload a window, use this method:

 

 Collapse
window.location.reload()

 

Close WindowYour can use one of the codes shown below:

 

 Collapse
<form> <input type="button" value="Close Window" onClick="window.close()"> </form> <a href="javascript:window.close()">Close Window</a>

 

LoadingThe basic syntax when loading new content into a window is:

 

 Collapse
window.location="test.htm"

This is the same as

 Collapse
<a href="test.htm>Try this </a>

Let's provide an example, where a confirm box will allow users to choose between going to two places:

 Collapse
<script> <!-- function ss() { var ok=confirm('Click "OK" to go to yahoo, "CANCEL" to go to hotmail') if (ok) location="http://www.yahoo.com" else location="http://www.hotmail.com" } //--> </script>

 

Remote Control WindowLet's say you have opened a new window from the current window. After that, you will wonder how to make a control between the two windows. To do this, we need to first give a name to the window.Look at below:

 

 Collapse
aa=window.open('test.htm','','width=200,height=200')

By giving this window a name "aa", it will give you access to anything that's inside this window from other windows. Whenever we want to access anything that's inside this newly opened window, for example, to write to this window, we would do this: aa.document.write("This is a test.").

Now, let's see an example of how to change the background color of another window:

 Collapse
<html><head><title></title></head> <body> <form> <input type="button" value="Open another page" onClick="aa=window.open('test.htm','','width=200,height=200')"> <input type="radio" name="x" onClick="aa.document.bgColor='red'"> <input type="radio" name="x" onClick="aa.document.bgColor='green'"> <input type="radio" name="x" onClick="aa.document.bgColor='yellow'"> </form> </body></html>

 

openerUsing "opener" property, we can access the main window from the newly opened window.

 

Let's create Main page:

 Collapse
<html> <head> <title></title> </head> <body> <form> <input type="button" value="Open another page" onClick="aa=window.open('test.htm','','width=100,height=200')"> </form> </body> </html>

Then create Remote control page (in this example, that is test.htm):

 Collapse
<html> <head> <title></title> <script> function remote(url){ window.opener.location=url } </script> </head> <body> <p><a href="#" onClick="remote('file1.htm')">File 1</a></p> <p><a href="#" onClick="remote('file2.htm')">File 2</a></p> </body> </html>

Try it now!

Back to top

Frame

One of the most popular uses of loading multiple frames is to load and change the content of more than one frame at once. Lets say we have a parent frame:

 Collapse
<html> <frameset cols="150,*"> <frame src="page1.htm" name="frame1"> <frame src="page2.htm" name="frame2"> </frameset> </html>

We can add a link in the child frame "frame1" that will change the contents of not only page1, but page2 too. Shown below is the html code for it:

 Collapse
<html> <body> <h2>This is page 1 </h2> <a href="page3.htm" onClick="parent.frame2.location='page4.htm'">Click Here</a> </body> </html>

Notice: You should use "parent.frameName.location" to access another frame. "parent" standards for the parent frame containing the frameset code.

Back to top

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

 

Nongjian Zhou
Senior Web Specialist.

 

 http://www.codeproject.com/KB/scripting/jsbeginner.aspx

sb
June 02, 2008

Car insurance is a type of cover that can be quite costly depending on your needs and circumstances, but this is a type of cover that is a legal requirement for drivers in the UK so no matter what the expense you have to get this cover if you wish to take your vehicle on the road. It is important to remember that there are ways and means of lowering your insurance premiums on car cover, however, so with a little thought and research you could save yourself a small fortune.

Below are some of the top ways in which you can save money on the cost of insurance cover:

1. Don't go for the first quote. Never assume that the first quote you get is going to be representative of all other quotes, as the cost of cover can vary widely from one provider to another. Make sure that you get at least three quotes from different providers before you make any decision – don’t feel tempted to rush into taking cover with the first insurance company that sends you details.

2. Remember that price comparison sites may not cover all providers. Many people have started to use price comparison sites to find their insurance cover, but you should bear in mind that these sites only cover a portion of the market and not all providers are on their databases. You should therefore be mindful that there may be a cheaper and more suitable policy available that is not on the price comparison site, so it may be worth checking individual providers to get your price down further.

3. Go for the most appropriate level of cover. If you have a new or expensive vehicle then you should opt for the top level of cover, which is fully comp. However, if you have an old car that has a low value then you can get away with taking out a lower level of cover, which will enable you to keep the cost of cover down whilst still fulfilling the legal requirement of having insurance.

4. Increase your excess. The amount of excess that you choose on your policy will make a difference to your premiums. If you choose to have a higher level of excess on your policy you can knock down your premiums significantly in some cases – just make sure that you do have enough money put aside to cover the excess in case you do need to make a claim.

5. Take the pass plus test if you have recently passed. New and younger drivers often find the cost of cover crippling. However, you can save a considerable amount on the cost of cover if you take the advances pass plus test after passing your standard test, with some insurers offering up to 35% off if you have passed this advanced course.

 

by: David Lynes - Loans4

sb
« older posts
aide


to aide

Recent Posts
Top Posts
Recent Comments
Categories
Archive
Syndication Tools
  • Subscribe to Flixya Blog Feed
  • Ping your RSS Feed
  • Add to Technorati Favorites!