/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Foster Wheeler Energia Oy - initial API and implementation *******************************************************************************/ package org.simantics.interop.test; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.window.IShellProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.part.ViewPart; import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.common.ResourceArray; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ServiceException; import org.simantics.db.exception.ValidationException; import org.simantics.db.request.Read; import org.simantics.db.service.SerialisationSupport; import org.simantics.interop.test.GraphChanges.Modification; import org.simantics.layer0.Layer0; import org.simantics.ui.dnd.LocalObjectTransfer; import org.simantics.ui.dnd.ResourceReferenceTransfer; import org.simantics.ui.dnd.ResourceTransferUtils; import org.simantics.ui.utils.ResourceAdaptionUtils; import org.simantics.utils.datastructures.BijectionMap; import org.simantics.utils.datastructures.Pair; import org.simantics.utils.ui.ExceptionUtils; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * Simple multiline text viewer for seeing differences in two subgraphs. * * @author Marko Luukkainen * */ public class GraphComparatorViewer extends ViewPart{ private Session session; private Composite composite; private Label resourceText1; private Label resourceText2; private Text text1; private Text text2; private List traversed = new ArrayList(); private List tested = new ArrayList(); private List strong = new ArrayList(); private List nonTraversed = new ArrayList(); private List nonTested = new ArrayList(); @Override public void createPartControl(Composite parent) { composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(2, false)); session = Simantics.getSession(); Composite topComposite = new Composite(composite, SWT.BORDER); topComposite.setLayout(new GridLayout(3, false)); text1 = new Text(composite, SWT.MULTI|SWT.V_SCROLL); text2 = new Text(composite, SWT.MULTI|SWT.V_SCROLL); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).span(2, 1).applyTo(topComposite); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text1); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text2); resourceText1 = createDropLabel(topComposite); resourceText2 = createDropLabel(topComposite); Button button = new Button(topComposite, SWT.PUSH); button.setText("Compare"); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { compare(); } }); defaultConf(); getViewSite().getActionBars().getToolBarManager().add(new Action("Config") { @Override public void run() { ConfigurationDialog dialog = new ConfigurationDialog(getSite().getShell()); dialog.open(); } }); } private void defaultConf() { traversed.clear(); tested.clear(); strong.clear(); nonTested.clear(); nonTraversed.clear(); try { session.syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); traversed.add(l0.ConsistsOf); tested.add(l0.IsWeaklyRelatedTo); nonTraversed.add(l0.InstanceOf); } }); } catch (Exception e) { ExceptionUtils.logAndShowError(e); } } private void compare() { text1.setText(""); text2.setText(""); final Resource r1 = (Resource)resourceText1.getData(); final Resource r2 = (Resource)resourceText2.getData(); if (r1 == null || r2 == null) { if (r1 == null) text1.setText("Missing input!"); if (r2 == null) text2.setText("Missing input!"); return; } session.asyncRequest(new ReadRequest() { @Override public void run(final ReadGraph graph) throws DatabaseException { GraphComparator comparator = new GraphComparator(r1,r2); comparator.addTested(tested); comparator.addTraversed(traversed); comparator.addNonTested(nonTested); comparator.addNonTraversed(nonTraversed); comparator.addStrong(strong); comparator.test(graph); BijectionMap map = comparator.getComparableStatements(); Map indices = new HashMap(); final StringBuilder sb1 = new StringBuilder(); final StringBuilder sb2 = new StringBuilder(); int index = 0; GraphChanges changes = comparator.getChanges(); for (Modification mod : changes.getModifications()) { { String sub; try { Statement s = mod.getLeftStm(); sub = NameUtils.getSafeName(graph, mod.getLeftSub()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsLeft(s)) { index++; indices.put(s, index); sb1.append("["+index + "] "); } sb1.append(sub + " - " + pre + " - " + obj); sb1.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb1.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } { String sub; try { Statement s = mod.getRightStm(); sub = NameUtils.getSafeName(graph, mod.getRightSub()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsRight(s)) { index = indices.get(map.getLeft(s)); sb2.append("["+index + "] "); } sb2.append(sub + " - " + pre + " - " + obj); sb2.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb2.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } } for (Statement s : changes.getDeletions()) { String sub; try { sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsLeft(s)) { index++; indices.put(s, index); sb1.append("["+index + "] "); } sb1.append(sub + " - " + pre + " - " + obj); sb1.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb1.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } for (Statement s : changes.getAdditions()) { String sub; try { sub = NameUtils.getSafeName(graph, s.getSubject()); String pre = NameUtils.getSafeName(graph, s.getPredicate()); String obj = NameUtils.getSafeName(graph, s.getObject()); if (map.containsRight(s)) { index = indices.get(map.getLeft(s)); sb2.append("["+index + "] "); } sb2.append(sub + " - " + pre + " - " + obj); sb2.append(" ["+s.getSubject().getResourceId() + " " + s.getPredicate().getResourceId() + " " + s.getObject().getResourceId()+"]"); sb2.append("\n"); } catch (ValidationException e) { e.printStackTrace(); } catch (ServiceException e) { e.printStackTrace(); } } Display.getDefault().asyncExec(new Runnable() { @Override public void run() { text1.setText(sb1.toString()); text2.setText(sb2.toString()); } }); } }); } @Override public void setFocus() { composite.setFocus(); } @Override public void dispose() { super.dispose(); } // copy-paste from GraphDebugger public Label createDropLabel(Composite parent) { final Label label = new Label(parent, SWT.BORDER); label.setAlignment(SWT.CENTER); label.setText("Drag a resource here to examine it in this debugger!"); label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY)); GridData data = new GridData(SWT.FILL, SWT.TOP, true, false); data.heightHint = 16; label.setLayoutData(data); // Add resource id drop support to the drop-area. DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY); dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() }); dropTarget.addDropListener(new DropTargetAdapter() { @Override public void dragEnter(DropTargetEvent event) { event.detail = DND.DROP_LINK; //label.setBackground(green); return; } @Override public void dragLeave(DropTargetEvent event) { label.setBackground(null); } @Override public void drop(DropTargetEvent event) { label.setBackground(null); ResourceArray[] data = parseEventData(event); if (data == null || data.length != 1) { event.detail = DND.DROP_NONE; return; } final ResourceArray array = data[0]; final Resource r = array.resources[array.resources.length - 1]; label.setData(r); try { label.setText(session.syncRequest(new Read() { @Override public String perform(ReadGraph graph) throws DatabaseException { return NameUtils.getSafeName(graph, r); } })); } catch (DatabaseException e) { e.printStackTrace(); } } private ResourceArray[] parseEventData(DropTargetEvent event) { //System.out.println("DATA: " + event.data); if (event.data instanceof String) { try { SerialisationSupport support = session.getService(SerialisationSupport.class); return ResourceTransferUtils.readStringTransferable(support, (String) event.data).toResourceArrayArray(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (DatabaseException e) { e.printStackTrace(); } } ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data); if (ret.length > 0) return ret; return null; } }); return label; } private class ConfigurationDialog extends Dialog { protected ConfigurationDialog(Shell parentShell) { super(parentShell); } @Override protected void createButtonsForButtonBar(Composite parent) { createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); createButton(parent, IDialogConstants.CLIENT_ID+1, "Load", false); createButton(parent, IDialogConstants.CLIENT_ID+2, "Save", false); } @Override protected void buttonPressed(int buttonId) { super.buttonPressed(buttonId); if (buttonId == IDialogConstants.CLIENT_ID+1) { //load FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(),SWT.OPEN); dialog.setFilterExtensions(new String[]{"*.xml"}); String filename = dialog.open(); if (filename == null) return; try { load(filename); traversedViewer.refresh(); testedViewer.refresh(); strongViewer.refresh(); nonTestedViewer.refresh(); nonTraversedViewer.refresh(); } catch (Exception e1) { MessageDialog.openError(Display.getCurrent().getActiveShell(), "Cannot load file" , e1.getMessage()); } } else if (buttonId == IDialogConstants.CLIENT_ID+2) { //save FileDialog dialog = new FileDialog(Display.getCurrent().getActiveShell(),SWT.SAVE); dialog.setFilterExtensions(new String[]{"*.xml"}); String filename = dialog.open(); if (filename == null) return; try { saveConf(filename); if (!filename.endsWith("xml")) filename += ".xml"; } catch (FileNotFoundException e1) { MessageDialog.openError(Display.getCurrent().getActiveShell(), "Cannot save file" , e1.getMessage()); } catch (IOException e1) { MessageDialog.openError(Display.getCurrent().getActiveShell(), "Cannot save file" , e1.getMessage()); } catch (DatabaseException e1) { MessageDialog.openError(Display.getCurrent().getActiveShell(), "Cannot save file" , e1.getMessage()); } } } private ListViewer traversedViewer; private ListViewer testedViewer; private ListViewer strongViewer; private ListViewer nonTraversedViewer; private ListViewer nonTestedViewer; @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); composite.setLayout(new FillLayout(SWT.VERTICAL)); Group group = new Group(composite, SWT.NONE); group.setText("Traversed"); group.setLayout(new FillLayout()); traversedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("Tested"); group.setLayout(new FillLayout()); testedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("Strong"); group.setLayout(new FillLayout()); strongViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("NonTraversed"); group.setLayout(new FillLayout()); nonTraversedViewer = new ListViewer(group); group = new Group(composite, SWT.NONE); group.setText("NonTested"); group.setLayout(new FillLayout()); nonTestedViewer = new ListViewer(group); traversedViewer.setContentProvider(new ResourceListContentProvider()); traversedViewer.setLabelProvider(new ResourceLabelProvider()); testedViewer.setContentProvider(new ResourceListContentProvider()); testedViewer.setLabelProvider(new ResourceLabelProvider()); strongViewer.setContentProvider(new ResourceListContentProvider()); strongViewer.setLabelProvider(new ResourceLabelProvider()); nonTraversedViewer.setContentProvider(new ResourceListContentProvider()); nonTraversedViewer.setLabelProvider(new ResourceLabelProvider()); nonTestedViewer.setContentProvider(new ResourceListContentProvider()); nonTestedViewer.setLabelProvider(new ResourceLabelProvider()); MenuManager strongManager = new MenuManager(); strongManager.setRemoveAllWhenShown(true); strongManager.addMenuListener(new ListPopupListener(strongViewer)); strongViewer.getControl().setMenu(strongManager.createContextMenu(strongViewer.getControl())); MenuManager nonTestedManager = new MenuManager(); nonTestedManager.setRemoveAllWhenShown(true); nonTestedManager.addMenuListener(new ListPopupListener(nonTestedViewer)); nonTestedViewer.getControl().setMenu(nonTestedManager.createContextMenu(nonTestedViewer.getControl())); MenuManager nonTraversedManager = new MenuManager(); nonTraversedManager.setRemoveAllWhenShown(true); nonTraversedManager.addMenuListener(new ListPopupListener(nonTraversedViewer)); nonTraversedViewer.getControl().setMenu(nonTraversedManager.createContextMenu(nonTraversedViewer.getControl())); MenuManager testedManager = new MenuManager(); testedManager.setRemoveAllWhenShown(true); testedManager.addMenuListener(new ListPopupListener(testedViewer)); testedViewer.getControl().setMenu(testedManager.createContextMenu(testedViewer.getControl())); MenuManager traversedManager = new MenuManager(); traversedManager.setRemoveAllWhenShown(true); traversedManager.addMenuListener(new ListPopupListener(traversedViewer)); traversedViewer.getControl().setMenu(traversedManager.createContextMenu(traversedViewer.getControl())); traversedViewer.setInput(traversed); testedViewer.setInput(tested); strongViewer.setInput(strong); nonTestedViewer.setInput(nonTested); nonTraversedViewer.setInput(nonTraversed); return composite; } } private class ListPopupListener implements IMenuListener { private ListViewer viewer; public ListPopupListener(ListViewer viewer) { this.viewer = viewer; } @Override public void menuAboutToShow(IMenuManager manager) { IStructuredSelection s = (IStructuredSelection)viewer.getSelection(); List list = (List)viewer.getInput(); manager.add(new AddAction(viewer, list)); if (!s.isEmpty()) { Object element = s.getFirstElement(); manager.add(new DeleteAction(viewer, list, element)); } } } private class DeleteAction extends Action { private Viewer viewer; private List list; private Object obj; public DeleteAction(Viewer viewer, List list, Object obj) { super("Delete"); this.list = list; this.obj = obj; this.viewer = viewer; } @Override public void run() { list.remove(obj); viewer.refresh(); } } private class AddAction extends Action { private Viewer viewer; private List list; public AddAction(Viewer viewer, List list) { super("Add"); this.list = list; this.viewer = viewer; } @Override public void run() { RelationChooseDialog dialog = new RelationChooseDialog(getSite().getShell()); if (dialog.open() == RelationChooseDialog.OK) { final String uri = dialog.getUri(); try { Resource res = session.syncRequest(new Read() { @Override public Resource perform(ReadGraph graph) throws DatabaseException { try { return graph.getResource(uri); } catch (Exception e) { return null; } } }); if (res != null) { list.add(res); viewer.refresh(); } else { MessageDialog.openError(getSite().getShell(), "Error", "Relation '" + uri + "' not found."); } } catch (Exception e) { } } } } private class RelationChooseDialog extends Dialog { private String uri = null; private Text text; public RelationChooseDialog(IShellProvider parentShell) { super(parentShell); } public RelationChooseDialog(Shell parentShell) { super(parentShell); } @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite) super.createDialogArea(parent); composite.setLayout(new GridLayout(2, false)); Label label = new Label(composite, SWT.NONE); label.setText("URI:"); text = new Text(composite, SWT.SINGLE | SWT.BORDER); text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); return composite; } @Override protected void okPressed() { uri = text.getText(); super.okPressed(); } public String getUri() { return uri; } } private class ResourceListContentProvider implements IStructuredContentProvider { @SuppressWarnings("unchecked") @Override public Object[] getElements(Object inputElement) { List list = (List)inputElement; return list.toArray(); } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public void dispose() { } } private class ResourceLabelProvider extends LabelProvider { @Override public String getText(Object element) { final Resource res = (Resource) element; try { return session.syncRequest(new Read() { @Override public String perform(ReadGraph graph) throws DatabaseException { return NameUtils.getSafeName(graph, res); } }); } catch (DatabaseException e) { return "Error: " + e.getMessage(); } } } private boolean saveConf(String filename) throws IOException, DatabaseException { File file = new File(filename); if (file.exists()) { if(!MessageDialog.openQuestion(Display.getCurrent().getActiveShell(), "Saving compare configuration", "Do you want to overwrite file'" + filename + "'?")) return false; } else { if(!file.createNewFile()) return false; } final PrintStream ps = new PrintStream(file); ps.println(""); ps.println(""); session.syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { for (Resource r : traversed) { ps.println(""); } for (Resource r : tested) { ps.println(""); } for (Resource r : strong) { ps.println(""); } for (Resource r : nonTraversed) { ps.println(""); } for (Resource r : nonTested) { ps.println(""); } } }); ps.println(""); ps.flush(); ps.close(); return true; } private void load(String filename) throws Exception { final ImportListener listener = new ImportListener(); XMLParser parser = new XMLParser(listener); parser.parse(filename); if (listener.getNonTested().size() + listener.getNonTraversed().size() + listener.getStrong().size() + listener.getTested().size() + listener.getTraversed().size() == 0) return; session.syncRequest(new ReadRequest() { @Override public void run(ReadGraph graph) throws DatabaseException { tested.clear(); traversed.clear(); strong.clear(); nonTested.clear(); nonTraversed.clear(); for (String uri : listener.getTested()) { tested.add(graph.getResource(uri)); } for (String uri : listener.getTraversed()) { traversed.add(graph.getResource(uri)); } for (String uri : listener.getStrong()) { strong.add(graph.getResource(uri)); } for (String uri : listener.getNonTested()) { nonTested.add(graph.getResource(uri)); } for (String uri : listener.getNonTraversed()) { nonTraversed.add(graph.getResource(uri)); } } }); } public static class ImportListener { private Collection traversed = new ArrayList(); private Collection tested = new ArrayList(); private Collection strong = new ArrayList(); private Collection nonTraversed = new ArrayList(); private Collection nonTested = new ArrayList(); public void done() { } public void addTraversed(String uri) { traversed.add(uri); } public void addTested(String uri) { tested.add(uri); } public void addStrong(String uri) { strong.add(uri); } public void addNonTraversed(String uri) { nonTraversed.add(uri); } public void addNonTested(String uri) { nonTested.add(uri); } public Collection getTraversed() { return traversed; } public Collection getNonTested() { return nonTested; } public Collection getNonTraversed() { return nonTraversed; } public Collection getStrong() { return strong; } public Collection getTested() { return tested; } } public static class XMLParser { private ImportListener listener; public XMLParser(ImportListener listener) { this.listener = listener; } public void parse(String filename) throws Exception{ ParserBean p = new ParserBean(); p.parse(filename); } private void handleElement(Stack parents, Element element) throws SAXException{ String name = element.qName; if(name.equals("traversed")) { for (Attribute a : element.attributes) { String propertyName = a.localName; String value = a.value; if (propertyName.equals("uri")) { listener.addTraversed(value); } } } else if(name.equals("tested")) { for (Attribute a : element.attributes) { String propertyName = a.localName; String value = a.value; if (propertyName.equals("uri")) { listener.addTested(value); } } } else if(name.equals("strong")) { for (Attribute a : element.attributes) { String propertyName = a.localName; String value = a.value; if (propertyName.equals("uri")) { listener.addStrong(value); } } } else if(name.equals("nontraversed")) { for (Attribute a : element.attributes) { String propertyName = a.localName; String value = a.value; if (propertyName.equals("uri")) { listener.addNonTraversed(value); } } } else if(name.equals("nontested")) { for (Attribute a : element.attributes) { String propertyName = a.localName; String value = a.value; if (propertyName.equals("uri")) { listener.addNonTested(value); } } } else if (name.equals("compare")) { } else { throw new SAXException("Unknown element '" + name + "'. The file does not contain ExtIO configuration."); } } public class ParserBean extends DefaultHandler implements Serializable { private static final long serialVersionUID = -4995836637014958966L; private Stack current = new Stack(); private Stack texts = new Stack(); public ParserBean() { super(); } public void parse(String filename) throws Exception { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); XMLReader reader = saxParser.getXMLReader(); FileReader file = new FileReader(filename); reader.setContentHandler(this); reader.parse(new InputSource(file)); listener.done(); } @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { current.push(new Element(uri,localName,name,attributes)); texts.push(new String()); } @Override public void endElement(String uri, String localName, String name) throws SAXException { Element e = null; String text = null; if (!current.empty()) { e = current.pop(); text = texts.pop(); } if (e != null) { e.setValue(text.trim()); } if (e != null) { handleElement(current,e); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (!current.empty()) { String text = texts.pop(); String value = new String( ch, start, length); text += value; texts.push(text); } } } public class Attribute { public String localName; public String qName; public String uri; public String value; public Attribute(String localName, String qName, String uri, String value) { this.localName = localName; this.qName = qName; this.uri = uri; this.value = value; } } public class Element implements Serializable { private static final long serialVersionUID = -5207502156942818875L; String uri; String localName; String qName; String value = null; List attributes = new ArrayList(); public Element(String uri, String localName, String qName, Attributes attributes) { this.uri = uri; this.localName = localName; this.qName = qName; for (int i = 0; i < attributes.getLength(); i++) { this.attributes.add(new Attribute(attributes.getLocalName(i),attributes.getQName(i),attributes.getURI(i),attributes.getValue(i))); } } public String getUri() { return uri; } public String getLocalName() { return localName; } public String getQName() { return qName; } public String getValue() { return value; } public List getAttributes() { return attributes; } public void setValue(String value) { this.value = value; } } } }