import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.xml.stream.*;
import java.awt.*;
import java.util.*;
import javax.xml.bind.*;
import javax.naming.spi.*;
import xmlclasses.*; // The bound XML classes used to turn XML elements into objects.
/**
* Example of StAX and JaXB use.
*
* Uses the following schema:
*
* <xsi:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.geog.leeds.ac.uk" xmlns="http://www.geog.leeds.ac.uk" elementFormDefault="qualified">
* <xsi:element name="map">
* <xsi:complexType>
* <xsi:sequence>
* <xsi:element name="polygon" minOccurs="0" maxOccurs="unbounded">
* <xsi:complexType>
* <xsi:sequence>
* <xsi:element name="points" type="xsi:string"/>
* </xsi:sequence>
* <xsi:attribute name="id" type="xsi:ID"/>
* </xsi:complexType>
* </xsi:element>
* </xsi:sequence>
* </xsi:complexType>
* </xsi:element>
* </xsi:schema>
*
*
*
* This should be saved in an xsd file in the same directory as this file
* and the following command run against it at the command line:
*
*
* xjc -p xmlclasses filename.xsd
*
*
* This should generate the following classes:
*
*
* Map.java
- The class representing the root element of the XML
* ObjectFactory.java
- Class for generating new copies of the XML root and sub-elements
* package-info.java
*
*
* Compile these (note they are in the xmlclasses package). This should also generate classes representing the sub-elements that
* are classes within Map.java. Provided you have the XSD file in the same directory
* as this XMLExamples.java file, the new files should be in a xmlclasses directory within the directory
* this java file and the XSD file is in.
* (NB: this can be any package name - we've just pick this here and used it throughout).
*
*
* You should then be able to compile and run this XMLExamples.java file, and use it to read in
* XML files like this:
*
*
* <?xml version="1.0" encoding="UTF-8"?>
* <?xml-stylesheet type="text/xsl" href="map2.xsl" ?>
* <map xmlns="http://www.geog.leeds.ac.uk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.geog.leeds.ac.uk map2.xsd">
* <polygon id="p1">
* <points>100,100 200,100 200,200 100,0 100,100 </points>
* </polygon>
* </map>
*
*
*
* @author Andrew Evans
* @version 1.0
*/
public class XMLExamples extends JFrame implements ActionListener {
private Polygon polygon = null; // Default polygon.
private String id = null;
private String saveStaxMenuItemText = "Save StaX"; // GUI Strings - normally from a properties file.
private String loadStaxMenuItemText = "Load StaX";
private String saveJaxbMenuItemText = "Save JaxB";
private String loadJaxbMenuItemText = "Load JaxB";
private String newJaxbMenuItemText = "New JaxB";
private String staxMenuText = "StaX";
private String jaxbMenuText = "JabX";
private boolean loaded = false;
private Panel panel = null;
private Label label = null;
/**
* Sets up the GUI.
*/
public XMLExamples () {
// General GUI.
super("XMLExamples");
setSize(300,300);
setLocation(200,200);
panel = new Panel();
panel.setSize(400,400);
getContentPane().add(panel, BorderLayout.CENTER);
label = new Label(" ");
getContentPane().add(label, BorderLayout.SOUTH);
// Menus.
MenuBar menuBar = new MenuBar();
//menuBar.setOpaque(false);
Menu staxMenu = new Menu(staxMenuText);
menuBar.add(staxMenu);
MenuItem saveStaxMenuItem = new MenuItem(saveStaxMenuItemText);
saveStaxMenuItem.addActionListener(this);
staxMenu.add(saveStaxMenuItem);
MenuItem loadStaxMenuItem = new MenuItem(loadStaxMenuItemText);
loadStaxMenuItem.addActionListener(this);
staxMenu.add(loadStaxMenuItem);
Menu jaxbMenu = new Menu(jaxbMenuText);
menuBar.add(jaxbMenu);
MenuItem saveJaxbMenuItem = new MenuItem(saveJaxbMenuItemText);
saveJaxbMenuItem.addActionListener(this);
jaxbMenu.add(saveJaxbMenuItem);
MenuItem loadJaxbMenuItem = new MenuItem(loadJaxbMenuItemText);
loadJaxbMenuItem.addActionListener(this);
jaxbMenu.add(loadJaxbMenuItem);
MenuItem newJaxbMenuItem = new MenuItem(newJaxbMenuItemText);
newJaxbMenuItem.addActionListener(this);
jaxbMenu.add(newJaxbMenuItem);
setMenuBar(menuBar);
// Setup default polygon.
int [] xs = {100,200,200,100,100};
int [] ys = {100,100,200,000,100};
polygon = new Polygon(xs,ys,xs.length);
id = "p1";
setVisible(true);
doLayout();
repaint();
}
/**
* Allows XMLExamples to be used as an ActionListener.
* Rather poorly, uses text items passed into constructor to determine
* method to call. Would be better using Actions.
* @param e
*/
public void actionPerformed(ActionEvent e) {
if (((MenuItem)e.getSource()).getLabel().equals(saveStaxMenuItemText)) {
writeStaxXML();
return;
}
if (((MenuItem)e.getSource()).getLabel().equals(loadStaxMenuItemText)) {
readStaxXML();
return;
}
if (((MenuItem)e.getSource()).getLabel().equals(saveJaxbMenuItemText)) {
writeJaxbXML();
return;
}
if (((MenuItem)e.getSource()).getLabel().equals(loadJaxbMenuItemText)) {
readJaxbXML();
return;
}
if (((MenuItem)e.getSource()).getLabel().equals(newJaxbMenuItemText)) {
newJaxbXML();
return;
}
}
/**
* Reads XML using Stax.
*/
private void readStaxXML() {
// Get inputStream for a file.
File file = getFileFromUser("Open");
if (file == null) return;
FileInputStream in = null;
try {
in = new FileInputStream(file);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Get an XML reader.
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader parser = null;
try {
parser = factory.createXMLStreamReader(in);
} catch (XMLStreamException xmlse) {
xmlse.printStackTrace();
}
// Parse the file.
int event = 0;
try {
while (true) {
event = parser.next();
// Having read the next XML component, check we're not EOF.
if (event == XMLStreamConstants.END_DOCUMENT) {
break;
}
// If not, parse XML element.
if (event == XMLStreamConstants.START_ELEMENT) {
// In our case here, we're only interested in the Polygon and Points
// components in the XML file.
if (parser.getLocalName().equals("polygon")) {
// Although we've only got one attribute, this
// shows how to use the attribute count.
int length = parser.getAttributeCount();
for (int i = 0; i < length; i++) {
if (parser.getAttributeLocalName(i).equals("id")) {
id = parser.getAttributeValue(i);
label.setText("id = " + id);
}
}
} else if (parser.getLocalName().equals("points")) {
polygon = buildPolygon(parser.getElementText());
loaded = true;
repaint();
}
} // End processing element.
} // End processing all elements.
parser.close();
} catch (XMLStreamException xmlse) {
xmlse.printStackTrace();
}
}
/**
* Write XML files using Stax.
**/
private void writeStaxXML() {
// Get outputStream for a file.
File file = getFileFromUser("Save");
if (file == null) return;
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Get an XML writer.
XMLOutputFactory factory = XMLOutputFactory.newInstance();
//factory.setProperty("javax.xml.stream.isRepairingNamespaces",new Boolean(true));
XMLStreamWriter writer = null;
// Setup XML writer.
try {
writer = factory.createXMLStreamWriter(out, "UTF-8");
//writer.setDefaultNamespace("http://www.geog.leeds.ac.uk");
} catch (XMLStreamException xmlse) {
xmlse.printStackTrace();
}
// Start writing.
try {
// XML header
writer.writeStartDocument("UTF-8", "1.0");
writer.writeProcessingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"map3.xsl\" ");
// Root element.
writer.writeStartElement("map");
// writer.writeNamespace("", "http://www.geog.leeds.ac.uk");
writer.writeNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
writer.writeAttribute("xsi:schemaLocation", "www.geog.leeds.ac.uk map3.xsd");
// Sub-element.
writer.writeStartElement("polygon");
writer.writeAttribute("id", id);
writer.writeStartElement("points");
// Sub-sub-element.
String points = getPoints(polygon);
writer.writeCharacters(points);
writer.writeEndElement();
// Close elements.
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
writer.close();
} catch (XMLStreamException xmlse) {
xmlse.printStackTrace();
}
// Close file.
try {
out.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
/**
* Reads XML using JaxB.
*/
private void readJaxbXML () {
// Get inputStream for a file.
File file = getFileFromUser("Open");
if (file == null) return;
FileInputStream in = null;
try {
in = new FileInputStream(file);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Unmarshall XML to objects.
try {
JAXBContext jaxbContext = JAXBContext.newInstance("xmlclasses");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
xmlclasses.Map map = null;
// In the following, the unmarshaller will attempt to unmarshall to
// the root element class. If it fails it generates a generic
// JAXBElement class object that can be interogated.
try {
map = (xmlclasses.Map) unmarshaller.unmarshal(in);
} catch (Exception ee) {
JAXBElement jaxElement = (JAXBElement) unmarshaller.unmarshal(in);
System.out.println("name = " + jaxElement.getName());
System.out.println("type = " + jaxElement.getDeclaredType());
}
// Get sub-elements and use.
// The getPolygon methods etc. are generated by the xjc tool that creates the
// appropriate classes.
// In the following 'poly' is the unmarshalled object and 'polygon' is a
// standard java.awt.polygon for drawing on the screen built by our 'buildPolygon' method
// in this class.
java.util.List polygonList = map.getPolygon();
xmlclasses.Map.Polygon poly = (xmlclasses.Map.Polygon) polygonList.get(0);
polygon = buildPolygon(poly.getPoints());
id = poly.getId();
label.setText("id = " + id);
loaded = true;
repaint();
} catch (JAXBException je) {
System.out.println(je.getMessage());
je.printStackTrace();
}
}
/**
* Writes XML using JaxB.
*/
private void writeJaxbXML () {
// Get outputStream for a file.
File file = getFileFromUser("Save");
if (file == null) return;
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
} catch (IOException ioe) {
ioe.printStackTrace();
}
try {
// Get a binding between XML and classes.
JAXBContext jaxbContext = JAXBContext.newInstance("xmlclasses");
// Use ObjectFactory created as part of binding to build a new
// object representing the root element of the XML.
xmlclasses.ObjectFactory factory = new xmlclasses.ObjectFactory();
xmlclasses.Map map = (xmlclasses.Map) factory.createMap();
// Fill it with appropriate sub-element classes.
xmlclasses.Map.Polygon poly = (xmlclasses.Map.Polygon) factory.createMapPolygon();
poly.setId(id);
poly.setPoints(getPoints(polygon));
java.util.List polygonList = map.getPolygon();
polygonList.add(poly);
// Marshall root element class to XML.
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, new Boolean(true));
marshaller.marshal(map, out);
} catch (JAXBException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* Generates a completely new object from the XML Schema, rather than reading one from XML file elements.
*/
private void newJaxbXML() {
// Get outputStream for a file.
File file = getFileFromUser("Save");
if (file == null) return;
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
} catch (IOException ioe) {
ioe.printStackTrace();
}
// Use the ObjectFactory created during binding to
// Generate a copy of the root element class and sub-elements.
// Fill them, combine them, and use them. Here we use them by
// marshalling to a XML file.
try {
JAXBContext jaxbContext = JAXBContext.newInstance("xmlclasses");
xmlclasses.ObjectFactory factory = new xmlclasses.ObjectFactory();
// Create the root element.
xmlclasses.Map map = (xmlclasses.Map) factory.createMap();
// Create and fill sub-elements.
xmlclasses.Map.Polygon poly = (xmlclasses.Map.Polygon) factory.createMapPolygon();
poly.setId("pt2");
poly.setPoints("100,100 100,200 200,200 200,100");
// Add the sub-elements to the list of sub-elements in the root element.
java.util.List polygonList = map.getPolygon();
polygonList.add(poly);
// Use the new object.
polygon = buildPolygon(poly.getPoints());
id = poly.getId();
label.setText("id = " + id);
loaded = true;
repaint();
// Write the new object as XML.
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(map, out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
/**
* Convenience method to get a file from a user.
* @param title - for dialog.
* @return File picked or null if cancelled.
*/
private File getFileFromUser (String title) {
JFileChooser chooser = new JFileChooser();
int returnVal = chooser.showDialog(this, title);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return chooser.getSelectedFile();
} else {
return null;
}
}
/**
* Convenience method to take in XML points and convert them to a java.awt.Polygon.
* Will parse points with space or comma delimiters.
* @param points should be in the form "x,y x,y x,y x,y".
*/
public Polygon buildPolygon(String points) {
StringTokenizer st = new StringTokenizer(points, " ,");
String tempStr = null;
int counter = 0;
int [] xs = new int[st.countTokens()/2];
int [] ys = new int[st.countTokens()/2];
while (st.hasMoreTokens()) {
tempStr = st.nextToken();
xs[counter] = Integer.parseInt(tempStr);
tempStr = st.nextToken();
ys[counter] = Integer.parseInt(tempStr);
counter++;
}
return new Polygon(xs,ys,xs.length);
}
/**
* Convenience method to return a String of points from a java.awt.Polygon.
* @return points will be in the form "x,y x,y x,y x,y".
*/
private String getPoints(Polygon polygon) {
int [] xs = polygon.xpoints;
int [] ys = polygon.ypoints;
String tempStr = "";
for (int i = 0; i < xs.length; i++) {
tempStr = tempStr + xs[i] + "," + ys[i] + " ";
}
tempStr.trim();
return tempStr;
}
/**
* If a polygon has been loaded into the system, paint it.
* @param g
*/
public void paint (Graphics g) {
if (loaded) {
Graphics jg = panel.getGraphics();
jg.translate(50,0);
jg.drawPolygon(polygon);
}
}
/**
* Just starts everything going.
* @param args
*/
public static void main (String args[]) {
new XMLExamples();
}
}