Concepts / Reading Element Content from a Document

Reading Element Content from a Document

A DOM representation of an XML document is created in Java with two statements: one builds a DocumentBuilder through DocumentBuilderFactory, and the other calls docReader.parse() on a File.

  • Programming

Starting From a Running Program

This article starts from code rather than from a definition. Imagine a short Java program that is handed an XML file and must turn that file into an object it can work with. The program does this in two statements. Once you see how those two statements hand work to each other, the idea of a DOM representation becomes concrete.

As you read, keep three questions in mind. Which line finishes its work first? Which line hands a value back? And what value does the variable xmldoc end up holding? Answering those three questions is the core skill this article builds.

What a DOM Representation Is For

Definition

A DOM representation of an XML document is a data structure that represents the whole XML document in memory. Once the file has been read into this structure, the program holds an object for the entire document rather than only a stream of raw text.

The purpose of this representation is to give the program something it can navigate and work with. Element content, which is the information stored inside an XML element, lives inside that in-memory object. The program reaches it through the object, not by scanning the file again from the top.

The source describes the DOM representation as an in-memory data structure, but it does not describe how that structure is laid out internally. You do not need those internal details to use it. What matters is the relationship between a variable and the object it refers to, which the next sections make precise.

Tracing the Two Statements

A DOM representation of an XML document is created in Java with two statements. The first statement builds a DocumentBuilder through DocumentBuilderFactory. The second statement calls docReader.parse() on a File. The first statement prepares the tool, and the second statement uses the tool on the file. The code below is an illustrative sketch of that two-statement pattern. The source describes the two statements in words, so the exact lines here are a generated example that matches the description.

java
Notes on the code
  • The import lines come from javax.xml.parsers, the package that holds both DocumentBuilder and DocumentBuilderFactory.
  • The File object names the XML file that will be read.
  • The factory produces the builder. The builder is the object that knows how to parse.
  • The parse call reads the file and returns the object for the entire document, which is stored in xmldoc.
Filethe XML file on diskparse()reads and builds the DOMDocumentheld by xmldocinputreturns
How does data move from the File through DocumentBuilder.parse() to the Document object that the program holds?

The diagram follows the data. The File is the input, the parse method is the processing step, and the Document object is the output that lands in xmldoc. The variable xmldoc is of type Document, and it refers to the object that the parse call returns.

Predicting What Happens to an Invalid File

Before reading on, try to predict this case. Suppose the file named by inputFile is not valid XML. Will docReader.parse() return a partial Document that holds whatever could be read, or will something else happen?

What do you think happens?

What do you think docReader.parse() does when the file is not legal XML?

  • It returns a partial Document with whatever was read

  • It throws an exception rather than returning a partial result

  • It returns null and the program continues quietly

Reveal answer
Answer:

It throws an exception rather than returning a partial result.

The source states that docReader.parse() throws an exception if the file cannot be read or does not contain a legal XML document. In either case the call does not hand back a partial result. Because the parse step does the reading and the validity check together, it is the place where a problem shows up.

Where Parsing Can Fail

The sequence has three steps: the factory is asked for a builder, the builder is obtained, and parse() is called on the file. The first two steps only prepare the tools. The failure point is the parse call, because that is the step that opens and reads the file and checks it for legal XML. The diagram shows the sequence and the branch that a failure takes.

DocumentBuilderFactoryproduces the builderDocumentBuilderknows how to parseparse(file)opens and reads the fileLegal XML?readable and validDocument returnedstored in xmldocException thrownno partial resultnewDocumentBuilderparse callreads and checksyesno
In what order do the factory, builder, and parse() calls run, and at which step does a failure stop the sequence and send an exception to the program?

The success path and the failure path differ at the parse step. On success, the Document is returned and stored in xmldoc, and the program can continue to read element content from it. On failure, control does not reach a Document assignment at all. This is why the parse call is the first place to inspect when XML parsing goes wrong.

Following xmldoc Through a Run

Worked example

Tracing the Variable xmldoc

A program runs the two-statement pattern on a file named library.xml. Trace which line finishes first, which line returns a value, and what xmldoc holds afterward.

  1. 1
    Create the factory

    DocumentBuilderFactory.newInstance() produces a factory object. No file has been read yet.

  2. 2
    Create the builder

    factory.newDocumentBuilder() uses the factory to produce a DocumentBuilder, stored in docReader. Still no file has been read.

  3. 3
    Call parse on the file

    docReader.parse(inputFile) opens library.xml, reads it, and builds the DOM representation. This is the line that does the real work.

  4. 4
    Assign the result

    If the parse succeeds, the returned Document object is stored in xmldoc. xmldoc is a variable of type Document and refers to that object.

Result

After a successful run, xmldoc refers to a Document object for the entire library.xml file. If the file were not legal XML, the parse step would throw an exception and no Document would be assigned.

Mistakes When Reading the Parse Call

  • Common mistake

    Assuming the factory reads the file

    Why it fails

    The factory is only responsible for producing the builder. Reading happens in the parse call.

    Do this instead

    Look for docReader.parse() when you want to know where the file is actually read.

  • Common mistake

    Expecting a partial Document when the XML is invalid

    Why it fails

    The source says parse() throws an exception if the file cannot be read or is not legal XML, rather than returning a partial result.

    Do this instead

    Treat an exception from parse() as the signal that no usable Document was produced.

  • Common mistake

    Treating the two statements as interchangeable

    Why it fails

    The first statement prepares the builder and the second statement uses it. Swapping their roles or skipping the first breaks the chain.

    Do this instead

    Keep the factory, builder, and parse call in that order when reading or writing the code.

  • Common mistake

    Thinking xmldoc holds the file text rather than an object for the whole document

Checking Your Reading of the Trace

EASY

A colleague says that the line DocumentBuilderFactory.newInstance() is the one that opens the XML file. Using the trace from this article, explain why that is incorrect and name the line that actually opens and reads the file.

Hints
  • Ask what the factory is responsible for, according to the source.
  • Look for the method call that takes the File as an argument.
  • Check which line causes the exception when the file is not legal XML.

Key Points to Carry Forward

  1. 1
    A DOM representation is an in-memory data structure for the whole XML document, and it is what the program works with after parsing.
  2. 2
    DocumentBuilderFactory produces a DocumentBuilder, and DocumentBuilder.parse() on a File does the reading.
  3. 3
    The parse call returns the object for the entire document, which the variable xmldoc of type Document refers to.
  4. 4
    If the file cannot be read or is not legal XML, parse() throws an exception rather than returning a partial result.

Key Takeaways

  • A DOM representation is an in-memory data structure for the whole XML document.
  • The factory produces the builder, and the builder's parse method reads the file.
  • parse() returns a Document object for the entire file, which xmldoc refers to.
  • A missing file or illegal XML makes parse() throw an exception instead of returning a partial result.