2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
* Copyright (C) 2004 University of Waikato, Hamilton, New Zealand
22
package weka.experiment.xml;
24
import java.beans.PropertyDescriptor;
25
import java.io.BufferedInputStream;
26
import java.io.BufferedOutputStream;
27
import java.io.FileInputStream;
28
import java.io.FileOutputStream;
29
import java.io.ObjectInputStream;
30
import java.io.ObjectOutputStream;
31
import java.util.Vector;
33
import org.w3c.dom.Element;
35
import weka.core.xml.XMLBasicSerialization;
36
import weka.core.xml.XMLDocument;
37
import weka.experiment.Experiment;
38
import weka.experiment.PropertyNode;
41
* This class serializes and deserializes an Experiment instance to and
43
* It omits the <code>options</code> from the Experiment, since these are handled
44
* by the get/set-methods. For the <code>Classifier</code> class with all its
45
* derivative classes it stores only <code>debug</code> and <code>options</code>.
46
* For <code>SplitEvaluator</code> and <code>ResultProducer</code> only the
47
* options are retrieved. The <code>PropertyNode</code> is done manually since
48
* it has no get/set-methods for its public fields.<br>
49
* Since there's no read-method for <code>m_ClassFirst</code> we always save it
50
* as <code>false</code>.
52
* @see Experiment#m_ClassFirst
54
* @author FracPete (fracpete at waikato dot ac dot nz)
55
* @version $Revision: 1.5 $
57
public class XMLExperiment extends XMLBasicSerialization {
58
/** the name of the classFirst property */
59
public final static String NAME_CLASSFIRST = "classFirst";
61
/** PropertyNode member */
62
public final static String NAME_PROPERTYNODE_VALUE = "value";
64
/** PropertyNode member */
65
public final static String NAME_PROPERTYNODE_PARENTCLASS = "parentClass";
67
/** PropertyNode member */
68
public final static String NAME_PROPERTYNODE_PROPERTY = "property";
71
* initializes the serialization
73
* @throws Exception if initialization fails
75
public XMLExperiment() throws Exception {
80
* generates internally a new XML document and clears also the IgnoreList and
81
* the mappings for the Read/Write-Methods
83
* @throws Exception if initializing fails
85
public void clear() throws Exception {
89
m_Properties.addIgnored(VAL_ROOT + ".options");
90
m_Properties.addIgnored(Experiment.class, "options");
93
m_Properties.addAllowed(weka.classifiers.Classifier.class, "debug");
94
m_Properties.addAllowed(weka.classifiers.Classifier.class, "options");
95
// we assume that classes implementing SplitEvaluator also implement OptionHandler
96
m_Properties.addAllowed(weka.experiment.SplitEvaluator.class, "options");
97
// we assume that classes implementing ResultProducer also implement OptionHandler
98
m_Properties.addAllowed(weka.experiment.ResultProducer.class, "options");
100
// read/write methods
101
m_CustomMethods.register(this, PropertyNode.class, "PropertyNode");
105
* enables derived classes to add other properties to the DOM tree, e.g.
106
* ones that do not apply to the get/set convention of beans.
108
* @param o the object that is serialized into XML
109
* @throws Exception if post-processing fails
111
protected void writePostProcess(Object o) throws Exception {
115
exp = (Experiment) o;
118
node = addElement(m_Document.getDocument().getDocumentElement(), NAME_CLASSFIRST, Boolean.class.getName(), false);
119
node.appendChild(node.getOwnerDocument().createTextNode(new Boolean(false).toString())); // TODO: get-Method for classFirst in Experiment???
123
* additional post-processing can happen in derived classes after reading
126
* @param o the object to perform some additional processing on
127
* @return the processed object
128
* @throws Exception if post-processing fails
130
protected Object readPostProcess(Object o) throws Exception {
136
exp = (Experiment) o;
139
children = XMLDocument.getChildTags(m_Document.getDocument().getDocumentElement());
140
for (i = 0; i < children.size(); i++) {
141
node = (Element) children.get(i);
142
if (node.getAttribute(ATT_NAME).equals(NAME_CLASSFIRST)) {
143
exp.classFirst(new Boolean(XMLDocument.getContent(node)).booleanValue());
152
* adds the given PropertyNode to a DOM structure.
154
* @param parent the parent of this object, e.g. the class this object is a member of
155
* @param o the Object to describe in XML
156
* @param name the name of the object
157
* @return the node that was created
158
* @throws Exception if the DOM creation fails
160
public Element writePropertyNode(Element parent, Object o, String name) throws Exception {
167
// for debugging only
169
trace(new Throwable(), name);
171
m_CurrentNode = parent;
173
pnode = (PropertyNode) o;
174
node = (Element) parent.appendChild(m_Document.getDocument().createElement(TAG_OBJECT));
175
node.setAttribute(ATT_NAME, name);
176
node.setAttribute(ATT_CLASS, pnode.getClass().getName());
177
node.setAttribute(ATT_PRIMITIVE, VAL_NO);
178
node.setAttribute(ATT_ARRAY, VAL_NO);
180
if (pnode.value != null)
181
invokeWriteToXML(node, pnode.value, NAME_PROPERTYNODE_VALUE);
182
if (pnode.parentClass != null)
183
invokeWriteToXML(node, pnode.parentClass.getName(), NAME_PROPERTYNODE_PARENTCLASS);
184
if (pnode.property != null)
185
invokeWriteToXML(node, pnode.property.getDisplayName(), NAME_PROPERTYNODE_PROPERTY);
187
// fix primitive values
188
if ( (pnode.value != null)
189
&& (pnode.property != null)
190
&& (pnode.property.getPropertyType().isPrimitive())) {
191
children = XMLDocument.getChildTags(node);
192
for (i = 0; i < children.size(); i++) {
193
child = (Element) children.get(i);
194
if (!child.getAttribute(ATT_NAME).equals(NAME_PROPERTYNODE_VALUE))
196
child.setAttribute(ATT_CLASS, pnode.property.getPropertyType().getName());
197
child.setAttribute(ATT_PRIMITIVE, VAL_YES);
205
* builds the PropertyNode from the given DOM node.
207
* @param node the associated XML node
208
* @return the instance created from the XML description
209
* @throws Exception if instantiation fails
210
* @see javax.swing.DefaultListModel
212
public Object readPropertyNode(Element node) throws Exception {
222
// for debugging only
224
trace(new Throwable(), node.getAttribute(ATT_NAME));
226
m_CurrentNode = node;
230
children = XMLDocument.getChildTags(node);
235
for (i = 0; i < children.size(); i++) {
236
child = (Element) children.get(i);
238
if (child.getAttribute(ATT_NAME).equals(NAME_PROPERTYNODE_VALUE)) {
239
if (stringToBoolean(child.getAttribute(ATT_PRIMITIVE)))
240
value = getPrimitive(child);
242
value = invokeReadFromXML(child);
244
if (child.getAttribute(ATT_NAME).equals(NAME_PROPERTYNODE_PARENTCLASS))
245
parentClass = XMLDocument.getContent(child);
246
if (child.getAttribute(ATT_NAME).equals(NAME_PROPERTYNODE_PROPERTY))
247
property = XMLDocument.getContent(child);
250
if (parentClass != null)
251
cls = Class.forName(parentClass);
256
result = new PropertyNode(value, new PropertyDescriptor(property, cls), cls);
258
result = new PropertyNode(value);
264
* for testing only. if the first argument is a filename with ".xml"
265
* as extension it tries to generate an instance from the XML description
266
* and does a <code>toString()</code> of the generated object.
267
* Otherwise it loads the binary file, saves the XML representation in a
268
* file with the original filename appended by ".xml" and once again in a
269
* binary file with the original filename appended by ".exp".
271
* @param args the commandline arguments
272
* @throws Exception if something goes wrong, e.g., file not found
274
public static void main(String[] args) throws Exception {
275
if (args.length > 0) {
276
// read xml and print
277
if (args[0].toLowerCase().endsWith(".xml")) {
278
System.out.println(new XMLExperiment().read(args[0]).toString());
280
// read binary and print generated XML
283
FileInputStream fi = new FileInputStream(args[0]);
284
ObjectInputStream oi = new ObjectInputStream(
285
new BufferedInputStream(fi));
286
Object o = oi.readObject();
289
//new XMLExperiment().write(System.out, o);
291
new XMLExperiment().write(new BufferedOutputStream(new FileOutputStream(args[0] + ".xml")), o);
292
// print to binary file
293
FileOutputStream fo = new FileOutputStream(args[0] + ".exp");
294
ObjectOutputStream oo = new ObjectOutputStream(
295
new BufferedOutputStream(fo));