提问人:Michael May 提问时间:4/18/2020 最后编辑:Michael May 更新时间:4/18/2020 访问量:581
Java 解析 XML
Java parsing XML
问:
这是 Core Java II Advanced Features(第 9 版)中的一个示例程序。此程序分析一个 XML 文件,其中包含 GridBagConstraints 对象的布局数据。但是,在运行时,程序崩溃并引发了许多异常。事实证明,这些异常似乎是由 XML 文件中的解析器捕获的一些错误引起的。setValidating() 方法设置为 true,因此根据 DTD 文件验证 XML。程序代码、XML 文件、DTD 和错误文本如下。很抱歉,这让这篇文章读起来有点长。非常感谢您的帮助。
package read;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class GridBagTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable () {
public void run () {
JFileChooser chooser = new JFileChooser("read");
chooser.showOpenDialog(null);
File file = chooser.getSelectedFile();
JFrame frame = new FontFrame(file);
frame.setTitle("GridBagTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
/**
* This frame contains a font selection dialog
* that is described by an XML file.
* @param filename the file containg the user
* interface components for the dialog.
*/
class FontFrame extends JFrame {
private GridBagPane gridbag;
private JComboBox<String> face;
private JComboBox<String> size;
private JCheckBox bold;
private JCheckBox italic;
@SuppressWarnings("unchecked")
public FontFrame (File file) {
gridbag = new GridBagPane(file);
add(gridbag);
face = (JComboBox<String>) gridbag.get("face");
size = (JComboBox<String>) gridbag.get("size");
bold = (JCheckBox) gridbag.get("bold");
italic = (JCheckBox) gridbag.get("italic");
face.setModel(new DefaultComboBoxModel<String>(new String[] {"Serif",
"SanSerif", "Monospaced", "Dialog", "DialogInput"}));
size.setModel(new DefaultComboBoxModel<String>(new String[] {"8", "10",
"12", "15", "18", "24", "36", "48"}));
ActionListener listener = new ActionListener() {
public void actionPerformed (ActionEvent event) {
setSample();
}
};
face.addActionListener(listener);
size.addActionListener(listener);
bold.addActionListener(listener);
italic.addActionListener(listener);
setSample();
pack();
}
/**
* This method sets the text sample to the selected font.
*/
public void setSample () {
String fontFace = face.getItemAt(face.getSelectedIndex());
int fontSize = Integer.parseInt(size.getItemAt(size.getSelectedIndex()));
JTextArea sample = (JTextArea) gridbag.get("sample");
int fontStyle = (bold.isSelected() ? Font.BOLD : 0) + (italic.isSelected() ? Font.ITALIC : 0);
sample.setFont(new Font(fontFace, fontStyle, fontSize));
sample.repaint();
}
}
package read;
import java.awt.*;
import java.beans.*;
import java.io.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
/**
* This panel users an XML file to describe its
* components and their grid bag layout positions.
*/
public class GridBagPane extends JPanel {
private GridBagConstraints constraints;
/**
* Construct a grid bag pane.
* @param filename the name of the XML file that
* desribes the pane's components and their positions
*/
public GridBagPane (File file) {
setLayout(new GridBagLayout());
constraints = new GridBagConstraints();
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
if (file.toString().contains("-schema")) {
factory.setNamespaceAware(true);
final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
}
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
parseGridbag(doc.getDocumentElement());
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Gets a component with a given name.
* @param name a component name
* @return the component with the given name, or null
* if no component in this grid bag pane has the given name
*/
public Component get(String name) {
Component[] components = getComponents();
for (int i = 0; i < components.length; i++) {
if (components[i].getName().equals(name))
return components[i];
}
return null;
}
/**
* Parse a gridbag element.
* @param e a gridbag element
*/
private void parseGridbag(Element e) {
NodeList rows = e.getChildNodes();
for (int i = 0; i < rows.getLength(); i++) {
Element row = (Element) rows.item(i);
NodeList cells = row.getChildNodes();
for (int j = 0; j < cells.getLength(); j++) {
Element cell = (Element) cells.item(j);
parseCell(cell, i, j);
}
}
}
/**
* Parse a cell element.
* @param e a cell element
* @param r the row of the cell
* @param c the column of the cell
*/
private void parseCell(Element e, int r, int c) {
// get attributes
String value = e.getAttribute("gridx");
if (value.length() == 0) // use default
{
if (c == 0)
constraints.gridx = 0;
else
constraints.gridx += constraints.gridwidth;
}
else
constraints.gridx = Integer.parseInt(value);
value = e.getAttribute("gridy");
if (value.length() == 0) // use default
constraints.gridy = r;
else
constraints.gridy = Integer.parseInt(value);
constraints.gridwidth = Integer.parseInt(e.getAttribute("gridwidth"));
constraints.gridheight = Integer.parseInt(e.getAttribute("gridheight"));
constraints.weightx = Integer.parseInt(e.getAttribute("weightx"));
constraints.weighty = Integer.parseInt(e.getAttribute("weighty"));
constraints.ipadx = Integer.parseInt(e.getAttribute("ipadx"));
constraints.ipady = Integer.parseInt(e.getAttribute("ipady"));
// use reflection to get integer values of static fields
Class<GridBagConstraints> cl = GridBagConstraints.class;
try {
String name = e.getAttribute("fill");
Field f = cl.getField(name);
constraints.fill = f.getInt(cl);
name = e.getAttribute("anchor");
f = cl.getField(name);
constraints.anchor = f.getInt(cl);
}
catch (Exception ex) // the reflection methods can throw various exceptions
{
ex.printStackTrace();
}
Component comp = (Component) parseBean((Element) e.getFirstChild());
add(comp, constraints);
}
/**
* Parse a bean element.
* @param e a bean element
*/
private Object parseBean(Element e) {
try {
NodeList children = e.getChildNodes();
Element classElement = (Element) children.item(0);
String className = ((Text) classElement.getFirstChild()).getData();
Class<?> cl = Class.forName(className);
Object obj = cl.newInstance();
if (obj instanceof Component)
((Component) obj).setName(e.getAttribute("id"));
for (int i = 1; i < children.getLength(); i++) {
Node propertyElement = children.item(i);
Element nameElement = (Element) propertyElement.getFirstChild();
String propertyName = ((Text) nameElement.getFirstChild()).getData();
Element valueElement = (Element) propertyElement.getLastChild();
Object value = parseValue(valueElement);
BeanInfo beanInfo = Introspector.getBeanInfo(cl);
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
boolean done = false;
for (int j = 0; !done && j < descriptors.length; j++) {
if (descriptors[j].getName().equals(propertyName)) {
descriptors[j].getWriteMethod().invoke(obj, value);
done = true;
}
}
}
return obj;
}
catch (Exception ex) // the relflection methods can throw various exceptions
{
ex.printStackTrace();
return null;
}
}
/**
* Parses a value element.
* @param e a value element
*/
private Object parseValue (Element e) {
Element child = (Element) e.getFirstChild();
if (child.getTagName().equals("bean"))
return parseBean(child);
String text = ((Text) child.getFirstChild()).getData();
if (child.getTagName().equals("int"))
return new Integer(text);
else if (child.getTagName().equals("boolean"))
return new Boolean(text);
else if (child.getTagName().equals("string"))
return text;
else
return null;
}
}
XML 文件:
<?xml version="1.0"?>
<!DOCTYPE gridbag SYSTEM "gridbag.dtd">
<gridbag>
<row>
<cell anchor="EAST">
<bean>
<class>javax.swing.JLabel</class>
<property>
<name>text</name>
<value>
<string>Face: </string>
</value>
</property>
</bean>
</cell>
<cell fill="HORIZONTAL" weightx="100">
<bean id="face">
<class>javax.swing.JComboBox</class>
</bean>
</cell>
<cell gridheight="4" fill="BOTH" weightx="100" weighty="100">
<bean id="sample">
<class>javax.swing.JTextArea</class>
<property>
<name>text</name>
<value>
<string>The quick brown fox jumps over the lazy dog</string>
</value>
</property>
<property>
<name>editable</name>
<value>
<boolean>false</boolean>
</value>
</property>
<property>
<name>lineWrap</name>
<value>
<boolean>true</boolean>
</value>
</property>
<property>
<name>border</name>
<value>
<bean>
<class>javax.swing.border.EtchedBorder</class>
</bean>
</value>
</property>
</bean>
</cell>
</row>
<row>
<cell anchor="EAST">
<bean>
<class>javax.swing.JLabel</class>
<property>
<name>text</name>
<value>
<string>Size: </string>
</value>
</property>
</bean>
</cell>
<cell fill="HORIZONTAL" weightx="100">
<bean id="size">
<class>javax.swing.JComboBox</class>
</bean>
</cell>
</row>
<row>
<cell gridwidth="2" weighty="100">
<bean id="bold">
<class>javax.swing.JCheckBox</class>
<property>
<name>text</name>
<value>
<string>Bold</string>
</value>
</property>
</bean>
</cell>
</row>
<row>
<cell gridwidth="2" weighty="100">
<bean id="italic">
<class>javax.swing.JCheckBox</class>
<property>
<name>text</name>
<value>
<string>Italic</string>
</value>
</property>
</bean>
</cell>
</row>
</gridbag>
DTD 文件:
<!ELEMENT gridbag (row)*>
<!ELEMENT row (cell)*>
<!ELEMENT cell (bean)>
<!ATTLIST cell gridx CDATA #IMPLIED>
<!ATTLIST cell gridy CDATA #IMPLIED>
<!ATTLIST cell gridwidth CDATA "1">
<!ATTLIST cell gridheight CDATA "1">
<!ATTLIST cell weightx CDATA "0">
<!ATTLIST cell weighty CDATA "0">
<!ATTLIST cell fill (NONE|BOTH|HORIZONTAL|VERTICAL) "NONE">
<!ATTLIST cell anchor (CENTER|NORTH|NORTHEAST|EAST|SOUTHEAST|SOUTH|SOUTHWEST|WEST|NORTHWEST) "CENTER">
<!ATTLIST cell ipadx CDATA "0">
<!ATTLIST cell ipady CDATA "0">
<!ELEMENT bean (class, property*)>
<!ATTLIST bean id ID #IMPLIED>
<!ELEMENT class (#PCDATA)>
<!ELEMENT property (name, value)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT value (int|string|boolean|bean)>
<!ELEMENT int (#PCDATA)>
<!ELEMENT string (#PCDATA)>
<!ELEMENT boolean (#PCDATA)>
错误输出:
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired. Parser will use a default ErrorHandler to print the first 0 errors. Please call the setErrorHandler method to fix this.
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=13: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=14: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=15: The content of element type "cell" must match "(bean)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=19: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=20: The content of element type "cell" must match "(bean)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=29: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=35: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=41: The content of element type "property" must match "(name,value)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=47: The content of element type "bean" must match "(class,property*)".
Error: URI=file:/Users/user01/java/CoreJava9_2/Chapter2/read/fontdialog.xml Line=48: The content of element type "value" must match "(int|string|boolean|bean)".
java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.DeferredTextImpl cannot be cast to org.w3c.dom.Element
at read.GridBagPane.parseGridbag(GridBagPane.java:76)
at read.GridBagPane.<init>(GridBagPane.java:45)
at read.FontFrame.<init>(GridBagTest.java:48)
at read.GridBagTest$1.run(GridBagTest.java:24)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at read.FontFrame.<init>(GridBagTest.java:55)
at read.GridBagTest$1.run(GridBagTest.java:24)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
感谢您不厌其烦地阅读以上所有内容并解释任何问题。
答:
1赞
CodeScale
4/18/2020
#1
在执行此操作之前,强制铸造 ->Element row = (Element) rows.item(i);
你必须检查它是否真的是一个Element
if(rows.item(i).getNodeType() == Node.ELEMENT_NODE){
评论
0赞
Michael May
4/18/2020
谢谢你的建议。在进一步处理之前,必须首先确保该项目是 Element。该程序的问题似乎是XML文件中特殊编码的空间,这混淆了解析器。我已将特殊空间替换为普通空间。现在问题顺利运行。
评论
Text
节点不能强制转换为Element
。<gridbag>
Text
Element
<row>
Text
Element
<row>
Element
<row>
Text
Element
Element