001package com.basilv.examples.dom4j;
002
003import java.io.File;
004
005import org.dom4j.*;
006import org.dom4j.io.SAXReader;
007
008public class MazeXmlConverter
009{
010  private static final String MAZE_ELEMENT = "maze";
011  private static final String HEIGHT_ATTRIBUTE = "height";
012  private static final String WIDTH_ATTRIBUTE = "width";
013  private static final String WALL_ELEMENT = "wall";
014  private static final String START_X_ATTRIBUTE = "startX";
015  private static final String START_Y_ATTRIBUTE = "startY";
016  private static final String END_X_ATTRIBUTE = "endX";
017  private static final String END_Y_ATTRIBUTE = "endY";
018
019  public String toXml(Maze maze) {
020    Document document = DocumentHelper.createDocument();
021    Element root = document.addElement(MAZE_ELEMENT)
022      .addAttribute(WIDTH_ATTRIBUTE, Integer.toString(maze.getSize().width))
023      .addAttribute(HEIGHT_ATTRIBUTE, Integer.toString(maze.getSize().height))
024      .addText(nullToEmpty(maze.getDescription()));
025
026    for (Wall wall : maze.getWalls()) {
027      root.addElement(WALL_ELEMENT)
028        .addAttribute(START_X_ATTRIBUTE, Integer.toString(wall.getStart().x))
029        .addAttribute(START_Y_ATTRIBUTE, Integer.toString(wall.getStart().y))
030        .addAttribute(END_X_ATTRIBUTE, Integer.toString(wall.getEnd().x))
031        .addAttribute(END_Y_ATTRIBUTE, Integer.toString(wall.getEnd().y));
032    }
033
034    return document.asXML();
035  }
036
037  private String nullToEmpty(String text) {
038    if (text == null) {
039      return "";
040    } else {
041      return text;
042    }
043  }
044  
045  public Maze fromXml(File xmlFile) {
046    SAXReader reader = new SAXReader();
047    try {
048      Document document = reader.read(xmlFile);
049      return fromXml(document);
050    } catch (DocumentException e) {
051      throw new RuntimeException("Error reading file [" + xmlFile.getAbsolutePath() + "].", e);
052    }
053  }
054
055  // For testing.
056  public Maze fromXml(String xml) {
057    try {
058      Document document = DocumentHelper.parseText(xml);
059      return fromXml(document);
060    } catch (DocumentException e) {
061      throw new RuntimeException("Error parsing xml string.", e);
062    }
063  }
064  
065  private Maze fromXml(Document document) {
066    Element root = document.getRootElement();
067
068    int width = getElementIntAttribute(root, WIDTH_ATTRIBUTE);
069    int height = getElementIntAttribute(root, HEIGHT_ATTRIBUTE);
070
071    Maze maze = new Maze(width, height);
072    maze.setDescription(root.getText());
073
074    for (Object elementObj : root.elements(WALL_ELEMENT)) {
075      Element element = (Element) elementObj;
076
077      int startX = getElementIntAttribute(element, START_X_ATTRIBUTE);
078      int startY = getElementIntAttribute(element, START_Y_ATTRIBUTE);
079      int endX = getElementIntAttribute(element, END_X_ATTRIBUTE);
080      int endY = getElementIntAttribute(element, END_Y_ATTRIBUTE);
081
082      maze.addWall(startX, startY, endX, endY);
083    }
084
085    return maze;
086  }
087
088  private int getElementIntAttribute(Element element, String attributeName) {
089    Attribute attribute = getNonNullAttributeForElement(element, attributeName);
090    return Integer.parseInt(attribute.getValue());
091  }
092
093  private Attribute getNonNullAttributeForElement(Element element, String attributeName) {
094    Attribute attribute = element.attribute(attributeName);
095    if (attribute == null) {
096      throw new RuntimeException("Element [" + element.getName() + "] missing attribute named [" + attributeName + "].");
097    }
098    return attribute;
099  }
100
101}