A little bit more...

Showing posts with label dom. Show all posts
Showing posts with label dom. Show all posts

Saturday, January 20, 2007

DOM Level 3 Load and Save

1. Introduction

Defined by w3 consortium, just as its name indicates, it serves as interfaces to objects that dealing with loading and saving DOM objects.

It’s noteworthy that various specific implementations doesn’t always fully support.

With java, it is well supported, though, some optional specifications are not supported (at least not always workabe from my experience). However, for web developers, there’s a quote from a book for you:

Now that XMLHttpRequest is being standardized, it seems likely that LSParser will never be supported by most browsers.

In addition, with java, you can also selectively use javax.xml.transform to deal with loading and saving DOM objects.

2. Breakdown

Cite from org.w3c.dom.ls:

DOMImplementationLS
DOMImplementationLS contains the factory methods for creating Load and Save objects.

LSInput
This interface represents an input source for data.

LSLoadEvent
This interface represents a load event object that signals the completion of a document load.

LSOutput
This interface represents an output destination for data.

LSParser
An interface to an object that is able to build, or augment, a DOM tree from various input sources.

LSParserFilter
LSParserFilters provide applications the ability to examine nodes as they are being constructed while parsing.

LSProgressEvent
This interface represents a progress event object that notifies the application about progress as a document is parsed.

LSResourceResolver
LSResourceResolver provides a way for applications to redirect references to external resources.

LSSerializer
A LSSerializer provides an API for serializing (writing) a DOM document out into XML.

LSSerializerFilter
LSSerializerFilters provide applications the ability to examine nodes as they are being serialized and decide what nodes should be serialized or not.

3. Examples

a. Write an instance of Document to a file with org.w3c.dom.ls:

DOMImplementationLS domImpl = (DOMImplementationLS)doc
.getImplementation();
LSSerializer serializer = domImpl.createLSSerializer();
LSOutput output = domImpl.createLSOutput();
output.setCharacterStream(new PrintWriter(fileName));
serializer.write(doc, output);

b. Write an instance of Document to a file with javax.xml.transform:

StreamResult sr = new StreamResult(new File(fileName));
Transformer t = TransformerFactory.newInstance().newTransformer();
t.transform(new DOMSource(doc), sr);

Note: it seems, from my experience, that example b can’t preserve the print friendly presentation.

Resources:

  1. Document Object Model (DOM) Level 3 Core Specification Version 1.0
  2. Document Object Model (DOM) Level 3 Load and Save Specification Version 1.0
  3. DOM Level 3
  4. Java Impl. Package org.w3c.dom.ls (src, api spec)

Monday, November 20, 2006

Basics of Javascript

Note:
My recent posts about basics or overview of something
mostly cite select matirials of sources listed in the Resources section of every
post. It only serves for personal study and learning. And if you like, you can
take any part or all of them as desired. It would be my pleasure.

Overview

Javascript is an html scripting language. In the official specification it is
called ECMAScript.

Built-in Features

Datatypes and Values

All numbers in JavaScript are represented as 64-bit floating-point values
(i.e., similar to double in java and C++).

Conversion between Strings and Numbers can be done in several ways in both
direction. Numbers are automatically converted to strings when needed, so are
strings converted to numbers.

Numbers to strings:

var n = 100;
var s = n + " bottles of beer.";

var n_as_string = n + "";

var string_value = String(number);

string_value = number.toString();

Strings to numbers:

var product = "21" * "2"; // get number 42

var number = string_value - 0;
(Note: adding zero to a string value
results in string concatenation)

var number = Number(string_value);

// And parseInt(), parseFloat.

In JavaScript, functions are values that can be manipulated
by JavaScript code. It means that functions can be stored in variables, arrays,
and objects, and it means that functions can be passed as arguments to other
functions.

Functions can be defined in three ways:

function square(x) { return x*x;}

var square = function(x) { return x*x; }
// function name here is
optional.

var square = new Function("x", "return x*x");
// awkward, less useful and
less efficient.

An object is a collection of named values. These named values are usually
referred to as properties of the object. Properties of objects are, in
many ways, just like JavaScript variables; they can contain any type of data,
including arrays, functions, and other objects. Objects in JavaScript can serve
as associative arrays (recall the same concept in Delphi/Pascal, if you
know that language); that is, they can associate arbitrary data values with
arbitrary strings.

image.width
image.height

image["width"]
image["height"]

Arrays may contain any type of JavaScript data, including references to other
arrays or to objects or functions. Also note that
JavaScript does not support multidimensional arrays,
except as arrays of arrays. Finally, because JavaScript is an untyped language,
the elements of an array do not all need to be
of the same type
, as they do in typed languages like Java.

A corresponding object class is defined for each of the three key
primitive datatypes
. That is, besides supporting the number, string,
and boolean datatypes, JavaScript also supports Number, String, and Boolean
classes. JavaScript can flexibly convert values from one type to another. When
you use a string in an object contexti.e., when you try to access a property or
method of the string, JavaScript internally creates a String wrapper
object for the string value
. Note that the String object created when
you use a string in an object context is a transient one.

Primitive types are manipulated by value, and reference types, as the
name suggests, are manipulated by reference
. Numbers and booleans are
easily manipulated at the low levels of the JavaScript interpreter. Objects, on
the other hand, are reference types. Arrays and functions, which are specialized
types of objects, are therefore also reference types.

Since strings (primitive type, not the wrapper) are immutable in JavaScript,
there is no way to tell whether strings are passed by value or by reference.

Variables

There's no fundamental difference in JavaScript between variables and
the properties of objects
.

When the JavaScript interpreter starts up, one of the first things it
does, before executing any JavaScript code, is create a global
object
. The properties of this object are the
global variables of JavaScript programs. When you declare a global JavaScript
variable, what you are actually doing is defining a property of the global
object.

The JavaScript interpreter initializes the global object with a number of
properties that refer to predefined values and functions. For example, the
Infinity, parseInt, and Math properties refer to the
number infinity, the predefined parseInt( ) function, and the
predefined Math object, respectively.

In top-level code (i.e., JavaScript code that is not part of a function), you
can use the JavaScript keyword this to refer to the global
object
.

In client-side JavaScript, the Window object
serves as the global object
for all JavaScript code contained in the
browser window it represents. This global Window object has a self-referential
window property that can be used instead of this to refer to
the global object. The Window object defines the core global properties, such as
parseInt and Math, and also global client-side properties,
such as navigator and screen.

For local variables, while the body of a function is executing, the function
arguments and local variables are stored as properties of another special
object. This object is known as the call object.

Each time the JavaScript interpreter begins to execute a function, it creates
a new execution context for that function. Thus,
JavaScript code that is not part of any function runs in an execution context
that uses the global object for variable definitions. A JavaScript
implementation may allow multiple "global" execution contexts
. The
obvious example is client-side JavaScript, in which each separate browser
window, or each frame within a window, defines a separate global execution
context.

Object Support

ECMAScript does not contain proper classes such as those in C++, Smalltalk,
or Java. An ECMAScript object is an unordered collection of properties each with
zero or more attributes.

It turns out that every JavaScript object includes an internal
reference to another object, known as its prototype
object. All
functions have a prototype property that is automatically created and
initialized when the function is defined. The initial value of the
prototype property is an object with a single property. This property
is named constructor and refers back to the constructor function with
which the prototype is associated.

Property inheritance occurs only when you read property values, not
when you write them
. If you set the property p in an
object o that inherits that property from its prototype, what
happens is that you create a new property p directly in
o. Now that o has its own property named
p, it no longer inherits the value of p from
its prototype.

Navigator Object

The JavaScript
navigator object
is the object representation of the client internet browser
or web navigator program that is being used. This object is the top level object
to all others.

DOM Object

Overview

The goal of the DOM group is to define a programmatic interface for XML and
HTML. It is platform- and language-neutral interface. The DOM is separated into
three parts: Core, HTML, and XML. The Core DOM provides a low-level set of
objects that can represent any structured document.

DOM is being designed at several levels:

  • "Level 1. This concentrates on the actual core, HTML, and XML document
    models. It contains functionality for document navigation and manipulation.

  • Level 2. Includes a style sheet object model, and defines functionality for
    manipulating the style information attached to a document. It also enables
    traversals on the document, defines an event model and provides support for XML
    namespaces.

  • Level 3. Will address document loading and saving, as well as content models
    (such as DTDs and schemas) with document validation support. In addition, it
    will also address document views and formatting, key events and event groups.
    First public working drafts are available.

  • Further Levels. These may specify some interface with the possibly
    underlying window system, including some ways to prompt the user. They may also
    contain a query language interface, and address multithreading and
    synchronization, security, and repository."

Resources

  1. ECMAScript
    Language Specification 3rd edition

  2. Ajax
    in Action

  3. The
    CTDP JavaScript Manual Version 0.6.0, December 31, 2000

  4. W3C Document Object Model
    (DOM)

  5. DOM
    objects and methods

  6. JavaScript - The Definitive Guide, 5th Edition


This is a rough draft and published temporarily.

Monday, November 13, 2006

Three ways of validating a xml document with Java

With the rollout of Java 5.0 last year, JAXP 1.3 was in place for use. And one of the new features provided by JAXP 1.3 is a brand new Schema Validation Framework.

The newly provided framework decouples the validation of an instance document as a process independent of parsing. The Validation APIs are in the new package javax.xml.validation and let developers obtain from a compiled schema a Validator or/and a Validator Handler which are used to validate xml against the given schema. Alternatively, a compiled schema instance could also be passed to any Reader/Parser to validate xml. So there're roughly two ways provided by the new Schema Validation Framework. And besides these two, setting the uncomplied schema source on Reader/Parser is also available due to the issue of backward compatibility. As we can see in the first article and the accompanying example codes listed in the Resources section, the newly introduced Validation Frame improves the performance, effiency and flexibility.

Below are simple code snippets to respectively illustrate how validating xml documents is done in these three ways.

1. Set uncompiled schema (since JAXP 1.2):
private static void saxParseJAXP1_2(String xmlFile, DefaultHandler dh,
String schemaFile) {
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(true);
SAXParser sp = spf.newSAXParser();
sp.setProperty(
http://java.sun.com/xml/jaxp/properties/schemaLanguage,
XMLConstants.W3C_XML_SCHEMA_NS_URI);
sp.setProperty(
"
http://java.sun.com/xml/jaxp/properties/schemaSource",
schemaFile);

sp.parse(new File(xmlFile), dh);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

2. Set compiled schema instance (since JAXP 1.3, FIX ME HERE)
private static void saxParseSetSchemaJAXP1_3(String xmlFile, DefaultHandler dh,
String schemaFile) {
try {
SchemaFactory sf = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File(schemaFile));
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setSchema(schema);
SAXParser sp = spf.newSAXParser();
sp.parse(new File(xmlFile), dh);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

3. Validator (since JAXP1.3)
private static void saxParseValidateJAXP1_3(String xmlFile,
ErrorHandler dh, String schemaFile) {
try {
SchemaFactory sf = SchemaFactory.newInstance(
XMLConstants.W3C_XML_SCHEMA_NS_URI);
Validator validator = sf.newSchema(
new File(schemaFile)).newValidator();

validator.setErrorHandler(dh);
validator.validate(new StreamSource(xmlFile));
} catch (Exception e) {
e.printStackTrace();
}

It's noteworthy that the first way and the second way can apply for both DOM source and SAX source, while the third way is usually only used to validate a SAX stream (FIX ME HERE).

Update (20061113):

Basics of using Schema

Be aware of the concept of xml target namespace and "source namespaces". The name defined in a schema are said to belong to its target namespace. Definitions and declarations in a schema can refer to names that may belong to other namespaces. In the fourth article those namespaces are referred to as "source namespaces". And here follows a little colour as to simple type and complex type. An element that doesn't contain attributes or other elements can be defined to be of a simple type, predefined or user-defined, such as string, integer, decimal, time, etc. Elements with attributes and embeded elements must have a complex type. There're a huge amount of details about XML Schema definition that are not covered here but can be found here.

Simple example

A xml instance document:
<?xml version = "1.0" encoding = "utf-8"?>
<SONGS xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:noNamespaceSchemaLocation='mySong.xsd'>
<SONG genre = "pop">
<TITLE > Hot Cop </TITLE>
<COMPOSER > Jacques Morali
</COMPOSER>
<COMPOSER>Henri Belolo</COMPOSER>
<COMPOSER>Victor Willis</COMPOSER>
<PRODUCER>Jacques Morali</PRODUCER>
<PUBLISHER>PolyGram Records</PUBLISHER>
<LENGTH>6:20</LENGTH>
<YEAR>1978</YEAR>
<ARTIST>Village People</ARTIST>
</SONG>
</SONGS>

The corresponding schema definition:
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
<xsd:element name="SONGS">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="SONG" minOccurs='1' maxOccurs='unbounded' />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="SONG">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="TITLE" type="xsd:string" />
<xsd:element name="COMPOSER" type="xsd:string" maxOccurs='unbounded' />
<xsd:element name="PRODUCER" type="xsd:string" maxOccurs='unbounded' />
<xsd:element name="PUBLISHER" type="xsd:string" maxOccurs='unbounded' />
<xsd:element name="LENGTH" type="xsd:string" />
<xsd:element name="YEAR" type="xsd:gYear" />
<xsd:element name="ARTIST" type="xsd:string" maxOccurs='unbounded' />
</xsd:sequence>
<xsd:attribute name="genre" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:schema>

Resources:

1. Easy and Efficient XML Processing: Upgrade to JAXP 1.3

2. Java 2 Platform Standard Edition 5.0 API Specification

3. Java 2 Platform Standard Edition 1.4.2 API Specification

4. The basics of using XML Schema to define elements

5. XML Schema Part 0: Primer Second Edition

Saturday, November 11, 2006

Comment on W3C DOM and various implementations in different PL

First I have to confess I'm quite unfamiliar with xml processing. I've only done it once extensively in Delphi due to a project I was involved in.

These days I'm studying tricks and technologies as to xml processing with java. So as I mentioned in a previous post I wrote about the overview on it. In particular, I mentioned the DOM way which is based on DOM, Document Object Model, a standard Object Model of XML maintained by the W3C Consortium. Here I first give some simple details about DOM itself.

For a simple xml document shown below:
<?xml version="1.0" encoding="UTF-8" ?>
<song genre="rock">
<name>My December</name>
<singer>Linkin Park</singer>
</song>

The DOM tree-like structure should be like this (E indicates a element node and T indicates a text node):
E:song
|--T:characters(whitespace)
|--E:name---T:characters(My December)
|--T:characters(whitespace)
|--E:singer---T:characters( Linkin Park)
|--T:characters(whitespace)

As depicted above, the root node song has five child nodes among wich two have their child nodes. I wanna emphasize the text node here. Before I start going deep into xml processing these days, I even don't know the existence of so-called text nodes. Because in Delphi, they're just ignored. So the DOM tree-like structure is like this:
E:song---E:name
|--E:singer

Only an element is called a node. I think this is quite intuitive, though definitely the official DOM structure is more theoretically complete. But with the white space and other text nodes the process of xml parsing is complicated. The example is worth a thousand words. Let's see how the simple xml document is parsed defferently in Java and Delphi:

In Java (exceptions are left unhandled):
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(<xml file name>);
Element root = doc.getDocumentElement();
NodeList list = root.getChildNodes();
// A simple helper method
printStr("name: " + list.item(1).getFirstChild().getNodeValue());
printStr("singer: " + list.item(3).getFirstChild().getNodeValue());

In Delphi:
var
XMLDoc: IXMLDocument;
XMLNode, CtlNode: IXMLNode;
i, index: integer;
str: string;
begin
str = '';
XMLDoc := TXMLDocument.Create(nil);
XMLNode = XMLDoc.ChildNodes.Nodes['song'];
for i := 0 to XMLNode.ChildNodes.Count - 1 do
begin
str := str + XMLNode.ChildNodes.Nodes[i].NodeValue;
end;
end;

Apparently, the Java version is more awkward and will be more complicated provided the xml document is very long. This is because the element nodes can't be sequentially accessed due to the existence of white space text nodes. In contrast, with text nodes ignored, the Delphi version is quite clear and adaptive to document of any size. As I know, besides Java many implementations (at least Javascript, as I know) of DOM are aware of the text nodes, especially the white space text nodes.

So various kinds of helper method are used by developers to improve this awkward situation.
Method 1:
private Node getNodeByName(final NodeList list, final String name) {

for (int i = 0; i < list.getLength(); i++) {

final Node node = list.item(i);

// to pass the white space node

if (name.equals(node.getNodeName())) {

return node;

}

}

return null; // not found

}

Method 2:

...

NodeList list = e.getChildNodes();

for (int i = 0; i < list.getLength(); i++) {

Node n = list.item(i);

  // to pass the white space node

if (!(n instanceof Element)) { continue; }

nsFixup((Element) n, map, false);

}

And I believe there must be more.

I really don't see any benifits of keeping the awareness of text nodes until now. But If you know, tell me please.

Friday, November 10, 2006

XML Processing With Java Overview

There’re basically two ways of processing xml with Java. One is the DOM way, that is tree-structure based way, and the other way is the SAX way that is event-driven stream based way. However, the bad thing is that there’re pros and cons for both ways, and the good thing is that we can use one of them in different situation to meet different needs.

The DOM way
DOM, Document Object Model, is the standard specification released by w3c consortium. It is a tree like structure which represents the structure of a XML document and is what what we often first parse a XML document into before we do any manipulation to it. It is quite intuitive for most programmers to manipulate. With it we can easily get what we want from a XML document, element names, attributes, values of elements, etc. But the price to pay is that before any manipulation we have to read the entire xml document and parse it into a DOM object during which everything must be stored in memory. This is inefficient and sometimes impossible, especially for extremely large documents. By the way, besides DOM, there’re some unofficially object models in use, such as JDOM, XOM, DOM4J and so on.

The SAX way

It is a stream like and event-based way. We can processing a document while we’re reading it. It is a very flexible but more complicated way than the DOM way. It is flexible because the SAX stream can be redirected to other process or document. It is complicated because the event handler (usually the DefaultHandler or ContentHandler) must be first written and then registered with the Parser (alternatively reader, or something like that). And there’re other disadvantages. Because it is processed like a stream, it is impossible to make changes to it or move backward to the data stream. But it is possilbe to make some simple structure (not the data itself) changes by using xsl transformation. In general, the SAX way is much faster than the DOM way.

What make up the “XML Processing”

So-called XML processing or sometimes called parsing consists of several aspects or procedures.
Validation
Data Modification and Retrieve
Transformation
Data Query

Examples

Higher Level Application
What are mentioned above are only those basic aspects about xml processing. Seen from a more global perspective, there’re many other higher level application of xml or xml processing.

Published temporarily and remains further refinement.

About Me

My photo
I'm finishing my master degree in Software Engineering, Computer Science. I believe and have been following what Forrest Gump's Mam said: you have to do the best with what god gave you.