Java разбор XML - PullRequest
       12

Java разбор XML

1 голос
/ 18 апреля 2020

вот пример программы из Core Java II Advanced Features (9-е издание). Эта программа анализирует файл XML, который содержит данные макета для объекта GridBagConstraints. Тем не менее, при запуске, программа потерпела крах, и был выдан ряд исключений. Оказалось, что эти исключения, по-видимому, были вызваны некоторыми ошибками, обнаруженными синтаксическим анализатором в файле XML. Метод setValidating () устанавливается в true, поэтому XML проверяется по файлу DTD. Код программы, файл 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 Ответ

1 голос
/ 18 апреля 2020

перед тем, как сделать это и вызвать кастинг -> Element row = (Element) rows.item(i);

Вы должны проверить, действительно ли это Element

if(rows.item(i).getNodeType() == Node.ELEMENT_NODE){
...