error on using xpath in java code - java

i'm trying to get result of expression of xpath , my xml file is like this :
<?xml version="1.0"?>
<all>
<test1>
</test1>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
an evil sorceress, and her own childhood to become queen
of the world.</description>
</book>
</catalog>
</all>
and my java code is :
public class xpath_test {
public static void main(String[] args) throws XPathExpressionException, SAXException, IOException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = (Document) builder.parse("C:\\Users\\HC\\Desktop\\dataset\\book.xml");
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("/all/catalog");
NodeList nodeList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getFirstChild().getNodeValue());
}
}
}
i got an exception :
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DeferredDocumentImpl cannot be cast to org.jdom2.Document
especially in this line Document doc = (Document) builder.parse("C:\\Users\\HC\\Desktop\\dataset\\book.xml");
knowing that i import import org.jdom2.Document;

try to use the standard interface
import org.w3c.dom.document
instead of
import org.jdom2.Document

Related

How to pass a XML document to XSL file using Javax.xml.transformer API?

I am using javax.xml.transform API to do XSL transformation . The API only allows one XML document as an input to apply transformation as below .
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
StringWriter stringWriter = new StringWriter();
File xml = new File("C:\\abc");
File xsl = new File("C:\\def.xsl");
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(xml);
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
StreamSource style = new StreamSource(xsl);
Transformer transformer = transformerFactory.newTransformer(style);
DOMSource source = new DOMSource(document);
Also , can pass simple String params as below , without any issue as below :
transformer.setParameter("mode", "CREATE");
But , i want to pass an XML Document as a parameter to the XSL file . I tried below code as suggested on one of SO pages , as below :
DocumentBuilder builder = factory.newDocumentBuilder();
final Document documentFile = builder.parse(xml2);
Map<String, Document> docs = new HashMap<String, Document>();
docs.put("lookup", documentFile);
transformer.setURIResolver(new DocumentURIResolver(docs));
And i set , the tag in XML to receive value as below :
<xsl:variable name="lookup" select="('documentFile')/> .
But its not working for me . Can anyone help me out with the correct pay to pass multiple XML documents to any XSL file via javax.xml.transform API ?
Update
Still stuck with the issue ,can any one let me how can i pass XML object into a XSLT 2.0 stylesheet as a param . I have tried different approaches but no luck still . I need to know a way out via JAVA xsl transform API .
I think your issue is in the XSLT. Change
<xsl:variable name="lookup" select="('documentFile')/> .
to
<xsl:variable name="lookup" select="document('lookup')/>
this will cause the transformer to make the DOM of your document accessible in the variable lookup. The key lookup comes from docs.put("lookup", documentFile);
Dynamically Pass Multiple XML Sources to XSL Transformation via URIResolver.
Full Working Example:
Be there three XML files: repo.xml, books.xml and articles.xml. The repo.xml contains status information about books and articles. The files articles.xml and books.xml contain title information about each item. The goal is to print status information of all books and articles together with the title information. The entries in all files are connected via id keys.
Find complete example at github or copy/paste the listings below.
repo.xml
<repository>
<book>
<id>1</id>
<status>available</status>
</book>
<book>
<id>2</id>
<status>lost</status>
</book>
<article>
<id>1</id>
<status>in transit</status>
</article>
</repository>
books.xml
<books>
<book id="1">
<title>Book One</title>
</book>
<book id="2">
<title>Book Two</title>
</book>
<book id="3">
<title>Book Three</title>
</book>
</books>
articles.xml
<articles>
<article id="1">
<title>Article One</title>
</article>
<article id="2">
<title>Article Two</title>
</article>
<article id="3">
<title>Article Three</title>
</article>
</articles>
join.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<titleStatusJoin>
<xsl:for-each select="//book">
<xsl:variable name="myId" select="id" />
<book>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('bookFile')//book">
<xsl:variable name="bookId" select="#id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</book>
</xsl:for-each>
<xsl:for-each select="//article">
<xsl:variable name="myId" select="id" />
<article>
<status>
<xsl:value-of select="status" />
</status>
<title>
<xsl:for-each select="document('articleFile')//article">
<xsl:variable name="bookId" select="#id" />
<xsl:choose>
<xsl:when test="$myId = $bookId">
<xsl:value-of select="title" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</title>
</article>
</xsl:for-each>
</titleStatusJoin>
</xsl:template>
</xsl:stylesheet>
Use this Java code...
#Test
public void useMultipleXmlSourcesInOneXsl3() {
InputStream xml = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/repo.xml");
InputStream xsl = Thread.currentThread().getContextClassLoader().getResourceAsStream("stack54335576/join3.xsl");
InputStream booksXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/books.xml");
InputStream articlesXml = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("stack54335576/articles.xml");
Document booksDom = readXml(booksXml);
Document articlesDom = readXml(articlesXml);
Map<String, Document> parameters = new HashMap<>();
parameters.put("bookFile", booksDom);
parameters.put("articleFile", articlesDom);
xslt(xml, xsl, parameters);
}
public final void xslt(InputStream xml, InputStream xsl, Map<String, Document> parameters) {
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xsl));
transformer.setURIResolver((href, base) -> new DOMSource(parameters.get(href)));
transformer.transform(new StreamSource(xml), new StreamResult(System.out));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Document readXml(InputStream xmlin) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
return db.parse(xmlin);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
...to produce this output
<?xml version="1.0" encoding="UTF-8"?>
<titleStatusJoin>
<book>
<status>available</status>
<title>Book One</title>
</book>
<book>
<status>lost</status>
<title>Book Two</title>
</book>
<article>
<status>in transit</status>
<title>Article One</title>
</article>
</titleStatusJoin>
Did you already try this ?
org.w3c.dom.Document doc = ... // Your xml document
transformer.setParameter("demo", doc.getDocumentElement());
(Answer expanded to handle passing in a parsed W3C DOM document via a URIResolver)
This can be done in pure XSLT/XPath using the version of the Xalan XSLT processor that is supplied with the JRE.
As an example, say if the name of one of the input documents is passed in as a parameter to the Transformer:
File parentDir = new File("c:\\dir");
StringWriter stringWriter = new StringWriter();
File xml = new File(parentDir, "input.xml");
File xsl = new File(parentDir, "xslt-document-param.xslt");
Source xsltSource = new StreamSource(xsl);
Source xmlSource = new StreamSource(xml);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsltSource);
transformer.setParameter("doc-name", "basic.xml");
transformer.transform(xmlSource, new StreamResult(stringWriter));
System.out.println(stringWriter);
This parameter can then be passed into the document() function in XPath as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
version="1.0"
exclude-result-prefixes="xalan">
<xsl:output
method="xml"
indent="yes"
xalan:indent-amount="2"/>
<xsl:param name="doc-name"/>
<xsl:template match="/">
<xsl:variable name="doc-content" select="document($doc-name)"/>
<parent>
<xsl:for-each select="$doc-content/basic/*">
<child>
<xsl:value-of select="name(.)"/>
</child>
</xsl:for-each>
</parent>
</xsl:template>
</xsl:stylesheet>
This is able to read this basic.xml (from the parameter):
<basic>
<one/>
<two/>
<three/>
</basic>
And transform it to:
<parent>
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
The parameter to the document() function is a URI. A relative path is resolved relative to the XSL file. Equally this could be a full URL, or resolved via a custom transformer.setURIResolver() as in the question.
(edit from here...)
To work with passing in a pre-parsed Document object to the XSLT, the URIResolver approach is able to handle passing this back to the document() function.
For example, with the lookup in the question:
File lookupXml = new File(parentDir, "basic.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(lookupXml);
Map<String, Document> docs = new HashMap<>();
docs.put("lookup", document);
transformer.setURIResolver((href, base) -> new DOMSource(docs.get(href)));
This XSL is able to iterate through the same basic.xml as above...
<xsl:template match="/">
<xsl:variable name="doc-content" select="document('lookup')"/>
<parent>
<xsl:for-each select="$doc-content/basic/*">
<child>
<xsl:value-of select="name(.)"/>
</child>
</xsl:for-each>
</parent>
</xsl:template>
... and output the same result.
Not sure about your issue , if you give usecase and ask how to solve will be more helpful insted of asking how to fix your code as we are not having end to end visiblity of your code and xml.
Following could be possible solution :
1) We can convert xml to string
try {
StringReader _reader = new StringReader("<xml>vkhan</xml>");
StringWriter _writer = new StringWriter();
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(
new javax.xml.transform.stream.StreamSource("styler.xsl"));//ur xsl
transformer.transform(
new javax.xml.transform.stream.StreamSource(_reader),
new javax.xml.transform.stream.StreamResult(_writer));
String result = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
2) Modify below code as per your requirments pass as List of object of call in for loop.
public class Data {
public static final Document transformXmlDocument(Document sourceDocument, InputStream xsltFile) {
DOMSource xmlSource = new DOMSource(sourceDocument);
StreamSource xsltSource = new StreamSource(xsltFile);
Document transformedData = null;
try {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltSource);
ByteArrayOutputStream output = new ByteArrayOutputStream();
StreamResult result = new StreamResult(output);
transformer.transform(xmlSource, result);
DocumentBuilder resultBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
transformedData = resultBuilder.parse(
new InputSource(
new StringReader(
new String(output.toByteArray())
)
)
);
} catch (Exception e) {
Log.e("XSLT Transformation", e.getMessage());
}
return transformedData;
}
}
https://gist.github.com/dazfuller/1559935/b84ee72db0e1de8ea25c54fbc744defbe4705ad9
Try to replace your <xsl:variable name="lookup" select="('documentFile')"/> instruction with <xsl:variable name="documentFile" select="document($lookup)"/> and pass your XML Document as a parameter with transformer.setParameter("lookup", "myfile.xml"); which means : load the document referenced by the lookup parameter into the documentFile variable.
See also Extract data from External XML file using XSL

Copy nodes in the same output xml file -java

1.This is my example file "example.xml"
<?xml version="1.0" encoding="UTF-8"?>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
<DATA>
2.This is my java code that parses the file "example.xml" :
public static void main(String argv[]) {
try {
Properties prop = System.getProperties();
File file = new File("E:/workspace/example.xml");
DocumentBuilderFactory dbildfactory =DocumentBuilderFactory.newInstance();
DocumentBuilder dbild = dbildfactory.newDocumentBuilder();
Document doc = dbild.parse(file);
doc.getDocumentElement().normalize();
NodeList nodeL = doc.getElementsByTagName("ALL");
for (int s = 0; s < nodeL.getLength(); s++) {
Node nodde = nodeL.item(s);
if (nodde.getNodeType() == Node.ELEMENT_NODE){
Element fstElmnt = (Element) nodde;
NodeList list = fstElmnt.getElementsByTagName("MARKE");
Element disp = (Element) list.item(0);
NodeList dispmarke = disp.getChildNodes();
System.out.println("<MARKE>" + ((Node)
dispmarke.item(0)).getNodeValue() + "</MARKE>");
String dispbrd = prop.getProperty("prop4");
((Node) dispmarke.item(0)).setNodeValue(dispbrd);
System.out.println("<MARKE>" + ((Node)
dispmarke.item(0)).getNodeValue() + "</MARKE>");
if(dispmarke.item(0).getNodeValue().equals("LEX") ){
NodeList nod = fstElmnt.getElementsByTagName("MARKE");
Element element = (Element) nod.item(0);
NodeList mod = element.getChildNodes();
System.out.println("<MARKE>" + ((Node) mod.item(0)).getNodeValue() + "</MARKE>");
prop.put("norm", "X300");
((Node) mod.item(0)).setNodeValue(prop.getProperty("norm"));
System.out.println("<MARKE>" + ((Node) mod.item(0)).getNodeValue() + "</MARKE>");
}
}
}
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
StreamResult console = new StreamResult(System.out);
StreamResult fil = new StreamResult(new File("E:/workspace/res/output.xml"));
transformer.transform(source, console);
transformer.transform(source, fil);
}
catch (Exception e) {
e.printStackTrace();
}
}
3.At this time, the nodes are saved to a new file "output.xml":
<?xml version="1.0" encoding="UTF-8"?>
<ALL>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
<DATA>
</ALL>
4.I would like that, there were several copies of nodes in file output.xml.
Everyone this node started after the last node:
<?xml version="1.0" encoding="UTF-8"?>
<ALL>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
<DATA>
</ALL>
<ALL>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
<DATA>
</ALL>
...
5.How can the easiest way to do this in Java? What loops used for this?
I had to fix your input XML to have a root element:
<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
</DATA>
</ROOT>
Then I could use XMLBeam (A data projection library, DISCLOSURE: I'm affiliated with this project) to
read the input,
wrap it into an ALL Element
duplicate the input and
print it out
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.xmlbeam.XBProjector;
import org.xmlbeam.XBProjector.Flags;
import org.xmlbeam.annotation.XBWrite;
import org.xmlbeam.dom.DOMAccess;
#SuppressWarnings("javadoc")
public class DuplicateNode {
// Projection to embed some nodes into an "ALL" element
public interface AllNodes {
#XBWrite("./*")
AllNodes setNodes(List<DOMAccess> nodes);
};
// Projection for the output document
public interface OutputProjection {
#XBWrite("/ROOT/*")
void setNodes(List<AllNodes> nodes);
};
public static void main(String[] args) throws IOException {
// Create the projector we will use to project the data
XBProjector projector = new XBProjector(Flags.TO_STRING_RENDERS_XML);
//Read all nodes from input document
List<DOMAccess> nodes =projector.io().url("res://example.xml").evalXPath("/ROOT/*").asListOf(DOMAccess.class);
// Create some copies
List<AllNodes> newNodeList = new LinkedList<AllNodes>();
newNodeList.add(projector.projectEmptyElement("ALL",AllNodes.class).setNodes(nodes));
newNodeList.add(projector.projectEmptyElement("ALL",AllNodes.class).setNodes(nodes));
//...
// Create an output projection that will take the copied nodes
OutputProjection outputProjection = projector.projectEmptyDocument(OutputProjection.class);
// set nodes to the output projection
outputProjection.setNodes(newNodeList);
// print it out (or write to file, stream,...)
System.out.println(outputProjection);
}
}
This program prints out:
<ROOT>
<ALL>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
</DATA>
</ALL>
<ALL>
<VER>7.0</VER>
<NATIONALITY>FIN</NATIONALITY>
<DATA>
<USER>ED</USER>
<PLZ>XXX</PLZ>
<BEGIN>2015-05-16</BEGIN>
<CURRENCY>90</CURRENCY>
<MARKE>KIA</MARKE>
</DATA>
</ALL>
</ROOT>

Parse nested XML nodes in Android

I have XML file like this:
<catalog>
<category>
<books>
<book>
<id>book1</id>
<description>short description</description>
<pages>number of pages</pages>
<author>Anonymous</author>
<name>Book title</name>
</book>
<book>
<id>book2</id>
<description>short description</description>
<pages>number of pages</pages>
<author>Anonymous</author>
<name>Book title</name>
</book>
</books>
</category>
<category>
<books>
<book>
<id>book3</id>
<description>short description</description>
<pages>number of pages</pages>
<author>Anonymous</author>
<name>Book title</name>
</book>
</books>
</category>
</catalog>
And I need an ArrayList with Categories and ArrayList with Books. Here are my Book and Category classes:
public class Book
{
private String id;
private String description;
private String pages;
private String author;
private String name;
}
public class Category {
private ArrayList<Book> books;
private String name;
}
What is the easiest way to do this? Using only android libraries and stuff would be better than using some libraries not for commercial use for my task. I tried some DOM parsers, but it didn't work good.
Actually it can easily be done using dom parser. Here is a stand alone java program to parse your XML file. I am printing values in standard output you can modify it to use in your android application.
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException {
File fXmlFile = new File("books");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
// iterate through <category> tags
NodeList categoryList = doc.getElementsByTagName("category");
for (int categoryNo=0;categoryNo<categoryList.getLength();categoryNo++) {
Element categoryNode = (Element)categoryList.item(categoryNo);
System.out.println("Category No " +categoryNo);
//iterate through <books> tags
NodeList booksList = categoryNode.getElementsByTagName("books");
for (int booksNo=0;booksNo<booksList.getLength();booksNo++) {
Element books = (Element)booksList.item(0);
// iterate through <book> tags
NodeList bookList = books.getElementsByTagName("book");
for(int bookNo=0;bookNo<bookList.getLength();bookNo++) {
Element bookElement = (Element)bookList.item(bookNo);
System.out.println(bookElement.getElementsByTagName("id").item(0).getTextContent());
System.out.println(bookElement.getElementsByTagName("description").item(0).getTextContent());
System.out.println(bookElement.getElementsByTagName("pages").item(0).getTextContent());
System.out.println(bookElement.getElementsByTagName("author").item(0).getTextContent());
System.out.println(bookElement.getElementsByTagName("name").item(0).getTextContent());
}
}
}
}
}
Have a look at android xml pull parser, this page has examples too
(it is a SAX parser)

how to get how many node with certain attributes with DOM

I have a task to parse an XML file with JDom in Eclipse. When I started to create the code, my code is only sufficient to get the length(how many) node with Tag name model. The task is more specific, I need to get the length of the node with tag name model which has attribute type. How should I modify my code to get the result?
This is part of my XML file
<container>
<models>
<model id="FM1" type="BoQ">
<meta
<phase phaseDesc="PRCR>SLCT>"/>
<domain domainCode="SPM.BOQ.RFP "/>
<levelOfDetail levelOfDetailCode="[4]"/>
</meta>
</model>
<model id="FM2" type="Object">
<meta>
<phase phaseDesc="PRCR>SLCT> "/>
<domain domainCode="BIM"/>
<levelOfDetail levelOfDetailCode="[4] "/>
</meta>
</model>
<model id="FM3">
<meta>
<phase phaseDesc="PRCR>SLCT>"/>
<domain domainCode="SPM.QTO"/>
<levelOfDetail levelOfDetailCode="[5]"/>
</meta>
</model>
<model id="FM4" type="BoQ">
<meta>
<phase phaseDesc="PRCR>SLCT>"/>
<domain domainCode="TSM.TSC"/>
<levelOfDetail levelOfDetailCode="[3]"/>
</meta>
</model>
</models>
<linkModels>
<linkModel id="LM1" type="QuantitySplit">
<meta>
<info>
<i k="ModelName" v="Linkmodell"/>
</info>
<domain domainCode="LKM.QSP" domainDesc="Link Model"/>
</meta>
<models>
<model id="FM1"/>
<model id="FM2"/>
<model id="FM3"/>
<model id="FM4"/>
</models>
</container>
public class xmldom {
public static void main(String[] args) {
Document xmlDoc = getDocument("./src/MMT_Angebot_Anfrage.xml");
System.out.println("Root: "+
xmlDoc.getDocumentElement().getNodeName());
NodeList model = xmlDoc.getElementsByTagName("model");
System.out.println("Number of Models " +
model.getLength());
String elementPhase = "phase";
String elementDomain = "domain";
String elementLOD = "levelOfDetail";
String attrPhase = "phaseCode";
String attrDomain = "domainCode";
String attrLOD = "levelOfDetailCode";
getElementAndAttrib(model, elementPhase, elementDomain, elementLOD, attrPhase, attrDomain, attrLOD);
}
private static Document getDocument(String docString) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
factory.setValidating(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(docString));
}
catch(Exception ex) {
System.out.println(ex.getMessage());
}
return null;
}
private static void getElementAndAttrib(NodeList model,
String elementPhase, String elementDomain, String elementLOD,
String attrPhase, String attrDomain, String attrLOD) {
try {
for(int i=0; i < model.getLength(); i++){
Node modelNode = model.item(i);
Element modelElement = (Element)modelNode;
NodeList phaseList = modelElement.getElementsByTagName(elementPhase);
NodeList domainList = modelElement.getElementsByTagName(elementDomain);
NodeList lodList = modelElement.getElementsByTagName(elementLOD);
Element phaseElement = (Element)phaseList.item(0);
Element domainElement = (Element)domainList.item(0);
Element lodElement = (Element)lodList.item(0);
NodeList elementList = phaseElement.getChildNodes();
System.out.println("=================================================");
System.out.println(attrPhase + " : "+ phaseElement.getAttribute(attrPhase));
System.out.println(attrDomain + " : "+ domainElement.getAttribute(attrDomain));
System.out.println(attrLOD + " : "+ lodElement.getAttribute(attrLOD));
}
}
catch(Exception ex) {
System.out.println(ex.getMessage());
}
}
}
You want to count the number of <model> elements that contains the type attribute? If, so XPath is the most suitable tool.
XPath xp = XPathFactory.newInstance().newXPath();
Double num = xp.evaluate("count(//model[#type])", doc, XPathConstants.NUMBER);
Btw, you are using DOM, not JDOM.

Parsing XML file using Xpath in jdk1.4

I found the following easy solution to extracting values from XML file.
import java.io.IOException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
public class XPathExample {
public static void main(String[] args)
throws ParserConfigurationException, SAXException,
IOException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("c:/temp/books.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr
= xpath.compile("//book[author='Neal Stephenson']/title/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
}
}
This uses xpath to extract all books title where the author is Neal Stephenson from the following xml
<inventory>
<book year="2000">
<title>Snow Crash</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553380958</isbn>
<price>14.95</price>
</book>
<book year="2005">
<title>Burning Tower</title>
<author>Larry Niven</author>
<author>Jerry Pournelle</author>
<publisher>Pocket</publisher>
<isbn>0743416910</isbn>
<price>5.99</price>
</book>
<book year="1995">
<title>Zodiac</title>
<author>Neal Stephenson</author>
<publisher>Spectra</publisher>
<isbn>0553573862</isbn>
<price>7.50</price>
</book>
<!-- more books... -->
</inventory>
Now this works fine on JDK5 but i am using jdk 1.4
Can this be converted to the java 1.4 equivalent?
All i am trying to do is extract a value from an xml element. For example, in the above xml, i just want something that is the equivalent of getElementByTag("title").
Thanks
Quick google resulted in links like this and this which confirm that JAXP can be downloaded separately and run on top of JDK 1.4.2. You might run into configuration problems as mentioned in the apache link. Good luck!

Categories