diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-09-26 17:33:13 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-09-26 17:33:13 +0100 |
| commit | be6fbc6f4e2f80552d3a7bab8677066d1fc858fc (patch) | |
| tree | 365f33cb3c09e838ff7bfab33609c919b73508ac /src/main/java | |
| parent | 0cdeb56333f61fc5769749106496106cfd8ffbfe (diff) | |
Add simple XML parsing
Diffstat (limited to 'src/main/java')
8 files changed, 193 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/mammoth/xml/ElementName.java b/src/main/java/org/zwobble/mammoth/xml/ElementName.java new file mode 100644 index 0000000..1d70c36 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/ElementName.java @@ -0,0 +1,8 @@ +package org.zwobble.mammoth.xml; + +import lombok.Value; + +@Value +public class ElementName { + private String localName; +} diff --git a/src/main/java/org/zwobble/mammoth/xml/SimpleSax.java b/src/main/java/org/zwobble/mammoth/xml/SimpleSax.java new file mode 100644 index 0000000..8165552 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/SimpleSax.java @@ -0,0 +1,54 @@ +package org.zwobble.mammoth.xml; + +import java.io.IOException; +import java.io.StringReader; +import java.util.stream.IntStream; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import static java.util.stream.Collectors.toMap; + +import lombok.val; + +public class SimpleSax { + public static void parseString(String value, SimpleSaxHandler handler) { + val parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + try { + val saxParser = parserFactory.newSAXParser(); + val xmlReader = saxParser.getXMLReader(); + xmlReader.setContentHandler(new DefaultHandler() { + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + final ElementName name = new ElementName(localName); + val attributesMap = IntStream.range(0, attributes.getLength()) + .boxed() + .collect(toMap( + index -> new ElementName(attributes.getLocalName(index)), + attributes::getValue + )); + handler.startElement(name, attributesMap); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + handler.endElement(); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + handler.characters(new String(ch, start, length)); + } + }); + xmlReader.parse(new InputSource(new StringReader(value))); + } catch (ParserConfigurationException | SAXException | IOException exception) { + throw new RuntimeException(exception); + } + } +} diff --git a/src/main/java/org/zwobble/mammoth/xml/SimpleSaxHandler.java b/src/main/java/org/zwobble/mammoth/xml/SimpleSaxHandler.java new file mode 100644 index 0000000..f56a940 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/SimpleSaxHandler.java @@ -0,0 +1,9 @@ +package org.zwobble.mammoth.xml; + +import java.util.Map; + +public interface SimpleSaxHandler { + void startElement(ElementName name, Map<ElementName, String> attributes); + void endElement(); + void characters(String string); +} diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlElement.java b/src/main/java/org/zwobble/mammoth/xml/XmlElement.java new file mode 100644 index 0000000..a49f5f8 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/XmlElement.java @@ -0,0 +1,30 @@ +package org.zwobble.mammoth.xml; + +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +@RequiredArgsConstructor +@EqualsAndHashCode +@ToString +public class XmlElement implements XmlNode { + public XmlElement(String name) { + this(name, ImmutableMap.of()); + } + + public XmlElement(String name, Map<String, String> attributes) { + this(name, attributes, ImmutableList.of()); + } + + @Getter + private final String name; + private final Map<String, String> attributes; + private final List<XmlNode> children; +} diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlElementBuilder.java b/src/main/java/org/zwobble/mammoth/xml/XmlElementBuilder.java new file mode 100644 index 0000000..16b4865 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/XmlElementBuilder.java @@ -0,0 +1,25 @@ +package org.zwobble.mammoth.xml; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +class XmlElementBuilder { + private final String name; + private final Map<String, String> attributes; + private final List<XmlNode> children; + + XmlElementBuilder(String name, Map<String, String> attributes) { + this.name = name; + this.attributes = attributes; + this.children = new ArrayList<>(); + } + + XmlElement build() { + return new XmlElement(name, attributes, children); + } + + void addChild(XmlNode node) { + children.add(node); + } +} diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlNode.java b/src/main/java/org/zwobble/mammoth/xml/XmlNode.java new file mode 100644 index 0000000..c91e100 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/XmlNode.java @@ -0,0 +1,5 @@ +package org.zwobble.mammoth.xml; + +public interface XmlNode { + +} diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlParser.java b/src/main/java/org/zwobble/mammoth/xml/XmlParser.java new file mode 100644 index 0000000..360c174 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/XmlParser.java @@ -0,0 +1,54 @@ +package org.zwobble.mammoth.xml; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Map; + +import static java.util.stream.Collectors.toMap; + +import lombok.val; + +public class XmlParser { + public static XmlElement parseString(String value) { + val nodeGenerator = new NodeGenerator(); + SimpleSax.parseString(value, nodeGenerator); + return nodeGenerator.getRoot(); + } + + private static class NodeGenerator implements SimpleSaxHandler { + private final Deque<XmlElementBuilder> elementStack; + + public NodeGenerator() { + elementStack = new ArrayDeque<>(); + } + + public XmlElement getRoot() { + return elementStack.getFirst().build(); + } + + @Override + public void startElement(ElementName name, Map<ElementName, String> attributes) { + val simpleAttributes = attributes + .entrySet() + .stream() + .collect(toMap( + entry -> entry.getKey().getLocalName(), + entry -> entry.getValue())); + val element = new XmlElementBuilder(name.getLocalName(), simpleAttributes); + elementStack.add(element); + } + + @Override + public void endElement() { + if (elementStack.size() > 1) { + val element = elementStack.removeLast(); + elementStack.getLast().addChild(element.build()); + } + } + + @Override + public void characters(String string) { + elementStack.getLast().addChild(new XmlTextNode(string)); + } + } +} diff --git a/src/main/java/org/zwobble/mammoth/xml/XmlTextNode.java b/src/main/java/org/zwobble/mammoth/xml/XmlTextNode.java new file mode 100644 index 0000000..0d63273 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/xml/XmlTextNode.java @@ -0,0 +1,8 @@ +package org.zwobble.mammoth.xml; + +import lombok.Value; + +@Value +public class XmlTextNode implements XmlNode { + private String value; +} |
