diff --git a/pom.xml b/pom.xml
index 0b5a9ea..f2d0360 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@
springmvc-springdata-mongodb
spring-mongodb-tutorial
spring-security-tutorial
+ xml-tutorials
diff --git a/xml-tutorials/pom.xml b/xml-tutorials/pom.xml
new file mode 100644
index 0000000..2201eb8
--- /dev/null
+++ b/xml-tutorials/pom.xml
@@ -0,0 +1,13 @@
+
+ 4.0.0
+
+ net.aimeizi
+ maven-framework-project
+ 1.0.0
+
+ xml-tutorials
+ pom
+
+ xml-stax-example
+
+
\ No newline at end of file
diff --git a/xml-tutorials/xml-stax-example/pom.xml b/xml-tutorials/xml-stax-example/pom.xml
new file mode 100644
index 0000000..7655cd2
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/pom.xml
@@ -0,0 +1,28 @@
+
+ 4.0.0
+
+ net.aimeizi
+ xml-tutorials
+ 1.0.0
+
+ xml-stax-example
+
+
+ 1.2.0
+
+
+
+
+ junit
+ junit
+ 4.6
+
+
+ stax
+ stax
+ ${stax.version}
+
+
+
+
\ No newline at end of file
diff --git a/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/Item.java b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/Item.java
new file mode 100644
index 0000000..a20ed42
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/Item.java
@@ -0,0 +1,55 @@
+package net.aimeizi.xml.stax.example;
+
+public class Item {
+ private String date;
+ private String mode;
+ private String unit;
+ private String current;
+ private String interactive;
+
+ public String getDate() {
+ return date;
+ }
+
+ public void setDate(String date) {
+ this.date = date;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
+ public String getUnit() {
+ return unit;
+ }
+
+ public void setUnit(String unit) {
+ this.unit = unit;
+ }
+
+ public String getCurrent() {
+ return current;
+ }
+
+ public void setCurrent(String current) {
+ this.current = current;
+ }
+
+ public String getInteractive() {
+ return interactive;
+ }
+
+ public void setInteractive(String interactive) {
+ this.interactive = interactive;
+ }
+
+ @Override
+ public String toString() {
+ return "Item [current=" + current + ", date=" + date + ", interactive="
+ + interactive + ", mode=" + mode + ", unit=" + unit + "]";
+ }
+}
diff --git a/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaXParser.java b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaXParser.java
new file mode 100644
index 0000000..0a31ca7
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaXParser.java
@@ -0,0 +1,125 @@
+package net.aimeizi.xml.stax.example;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+
+import org.junit.Test;
+
+/**
+ * @see http://www.vogella.com/articles/JavaXML/article.html
+ * @author scott
+ *
+ */
+public class StaXParser {
+ static final String DATE = "date";
+ static final String ITEM = "item";
+ static final String MODE = "mode";
+ static final String UNIT = "unit";
+ static final String CURRENT = "current";
+ static final String INTERACTIVE = "interactive";
+
+ @SuppressWarnings({ "unchecked"})
+ public List- readConfig(InputStream in) {
+ List
- items = new ArrayList
- ();
+ try {
+ // First create a new XMLInputFactory
+ XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+ // Setup a new eventReader
+ XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
+ // Read the XML document
+ Item item = null;
+
+ while (eventReader.hasNext()) {
+ XMLEvent event = eventReader.nextEvent();
+
+ if (event.isStartElement()) {
+ StartElement startElement = event.asStartElement();
+ // If we have a item element we create a new item
+ if (startElement.getName().getLocalPart() == (ITEM)) {
+ item = new Item();
+ // We read the attributes from this tag and add the date
+ // attribute to our object
+ Iterator attributes = startElement
+ .getAttributes();
+ while (attributes.hasNext()) {
+ Attribute attribute = attributes.next();
+ if (attribute.getName().toString().equals(DATE)) {
+ item.setDate(attribute.getValue());
+ }
+
+ }
+ }
+
+ if (event.isStartElement()) {
+ if (event.asStartElement().getName().getLocalPart()
+ .equals(MODE)) {
+ event = eventReader.nextEvent();
+ item.setMode(event.asCharacters().getData());
+ continue;
+ }
+ }
+ if (event.asStartElement().getName().getLocalPart()
+ .equals(UNIT)) {
+ event = eventReader.nextEvent();
+ item.setUnit(event.asCharacters().getData());
+ continue;
+ }
+
+ if (event.asStartElement().getName().getLocalPart()
+ .equals(CURRENT)) {
+ event = eventReader.nextEvent();
+ item.setCurrent(event.asCharacters().getData());
+ continue;
+ }
+
+ if (event.asStartElement().getName().getLocalPart()
+ .equals(INTERACTIVE)) {
+ event = eventReader.nextEvent();
+ item.setInteractive(event.asCharacters().getData());
+ continue;
+ }
+ }
+ // If we reach the end of an item element we add it to the list
+ if (event.isEndElement()) {
+ EndElement endElement = event.asEndElement();
+ if (endElement.getName().getLocalPart() == (ITEM)) {
+ items.add(item);
+ }
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }finally{
+ if(in!=null){
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return items;
+ }
+
+
+ @Test
+ public void test(){
+ List
- readConfig = readConfig(ClassLoader.getSystemResourceAsStream("config.xml"));
+ for (Item item : readConfig) {
+ System.out.println(item);
+ }
+ }
+
+
+}
diff --git a/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxQueryXML.java b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxQueryXML.java
new file mode 100644
index 0000000..e3e4b15
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxQueryXML.java
@@ -0,0 +1,71 @@
+package net.aimeizi.xml.stax.example;
+
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+/**
+ * @see http://www.vogella.com/articles/JavaXML/article.html
+ * stax XPath query
+ * @author scott
+ *
+ */
+public class StaxQueryXML {
+
+ public void query() throws ParserConfigurationException, SAXException,IOException, XPathExpressionException {
+ // Standard of reading a XML file
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ DocumentBuilder builder;
+ Document doc = null;
+ XPathExpression expr = null;
+ builder = factory.newDocumentBuilder();
+ doc = builder.parse(ClassLoader.getSystemResourceAsStream("person.xml"));
+
+ // Create a XPathFactory
+ XPathFactory xFactory = XPathFactory.newInstance();
+
+ // Create a XPath object
+ XPath xpath = xFactory.newXPath();
+
+ // Compile the XPath expression
+ expr = xpath.compile("//person[firstname='Lars']/lastname/text()");
+ // Run the query and get a nodeset
+ Object result = expr.evaluate(doc, XPathConstants.NODESET);
+
+ // Cast the result to a DOM NodeList
+ NodeList nodes = (NodeList) result;
+ for (int i = 0; i < nodes.getLength(); i++) {
+ System.out.println(nodes.item(i).getNodeValue());
+ }
+
+ // New XPath expression to get the number of people with name lars
+ expr = xpath.compile("count(//person[firstname='Lars'])");
+ // Run the query and get the number of nodes
+ Double number = (Double) expr.evaluate(doc, XPathConstants.NUMBER);
+ System.out.println("Number of objects " + number);
+
+ // Do we have more then 2 people with name lars?
+ expr = xpath.compile("count(//person[firstname='Lars']) >2");
+ // Run the query and get the number of nodes
+ Boolean check = (Boolean) expr.evaluate(doc, XPathConstants.BOOLEAN);
+ System.out.println(check);
+
+ }
+
+ @Test
+ public void test() throws XPathExpressionException,ParserConfigurationException, SAXException, IOException {
+ query();
+ }
+}
diff --git a/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxWriter.java b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxWriter.java
new file mode 100644
index 0000000..034c336
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxWriter.java
@@ -0,0 +1,91 @@
+package net.aimeizi.xml.stax.example;
+
+import java.io.FileOutputStream;
+
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartDocument;
+import javax.xml.stream.events.StartElement;
+
+import org.junit.Test;
+
+public class StaxWriter {
+
+ private String configFile;
+
+ public void setFile(String configFile) {
+ this.configFile = configFile;
+ }
+
+ public void saveConfig() throws Exception {
+ // Create a XMLOutputFactory
+ XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
+ // Create XMLEventWriter
+ XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(configFile));
+ // Create a EventFactory
+ XMLEventFactory eventFactory = XMLEventFactory.newInstance();
+
+ //XMLEvent end = eventFactory.createDTD("\n");
+
+ // Create and write Start Tag
+ StartDocument startDocument = eventFactory.createStartDocument();
+ eventWriter.add(startDocument);
+
+ // Create config open tag
+ StartElement configStartElement = eventFactory.createStartElement("","", "config");
+ eventWriter.add(configStartElement);
+
+ //eventWriter.add(end);
+
+ // Write the different nodes
+ createNode(eventWriter, "mode", "1");
+ createNode(eventWriter, "unit", "901");
+ createNode(eventWriter, "current", "100");
+ createNode(eventWriter, "interactive", "5");
+
+ eventWriter.add(eventFactory.createEndElement("", "", "config"));
+
+ //eventWriter.add(end);
+
+ eventWriter.add(eventFactory.createEndDocument());
+ eventWriter.close();
+ }
+
+ private void createNode(XMLEventWriter eventWriter, String name,
+ String value) throws XMLStreamException {
+
+ XMLEventFactory eventFactory = XMLEventFactory.newInstance();
+
+ //XMLEvent end = eventFactory.createDTD("\n");
+ //XMLEvent tab = eventFactory.createDTD("\t");
+
+ // Create Start node
+ StartElement sElement = eventFactory.createStartElement("", "", name);
+ //eventWriter.add(tab);
+ eventWriter.add(sElement);
+ // Create Content
+ Characters characters = eventFactory.createCharacters(value);
+ eventWriter.add(characters);
+ // Create End node
+ EndElement eElement = eventFactory.createEndElement("", "", name);
+ eventWriter.add(eElement);
+ //eventWriter.add(end);
+
+ }
+
+ @Test
+ public void test() {
+ StaxWriter configFile = new StaxWriter();
+ configFile.setFile("configx.xml");
+ try {
+ configFile.saveConfig();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxXmlUtil.java b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxXmlUtil.java
new file mode 100644
index 0000000..14dc058
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/java/net/aimeizi/xml/stax/example/StaxXmlUtil.java
@@ -0,0 +1,226 @@
+package net.aimeizi.xml.stax.example;
+
+import java.io.InputStream;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.EventFilter;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * 使用Stax解析xml
+ * @author scott
+ *
+ */
+public class StaxXmlUtil {
+
+
+ /**
+ * 基于光标的方式解析XML
+ */
+ @Test
+ public void cursorParseXML() throws Exception {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ InputStream is = ClassLoader.getSystemResourceAsStream("books.xml");
+ XMLStreamReader reader = factory.createXMLStreamReader(is);
+ while(reader.hasNext()) {
+ int type = reader.next();
+ //处理不同的节点类型
+ //处理开始节点,如,
+ if(type == XMLStreamConstants.START_ELEMENT) {
+ String name = reader.getName().toString();
+ System.out.println("<" + name + ">");
+ //打印节点中的第一个属性category值"COOKING"
+ if(name.equals("book")){
+ System.out.println("节点属性值为" + reader.getAttributeName(0) + "=" + reader.getAttributeValue(0));
+ }
+ if(name.equals("title")) {
+ System.out.println("书籍[" + reader.getElementText() + "]");
+ }
+ if(name.equals("price")) {
+ System.out.println("的价格为[" + reader.getElementText() + "]");
+ }
+ //打印文本节点的内容,注意各xml标签中的空白部分也属于文本节点..并且文本节点是没有name的,所以不能getName
+ } else if(type == XMLStreamConstants.CHARACTERS) {
+ System.out.println("文本节点值=[" + reader.getText().trim() + "]");
+ //处理结束节点,如,
+ } else if(type == XMLStreamConstants.END_ELEMENT) {
+ System.out.println("" + reader.getName() + ">");
+ }
+ }
+ //最后处理完了xml,记得关闭..但不能提前关闭,因为Stax是读一点流就解析一点的
+ is.close();
+ }
+
+
+ /**
+ * 基于迭代模型的方式解析XML
+ */
+ @Test
+ public void iteratorParseXML() throws Exception {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ InputStream is = ClassLoader.getSystemResourceAsStream("books.xml");
+ XMLEventReader reader = factory.createXMLEventReader(is);
+ int iteratorNum = 0; //统计遍历的次数
+ while(reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ if(event.isStartElement()) { //通过XMLEvent判断节点类型
+ String name = event.asStartElement().getName().toString(); //通过event.asxxx转换节点
+ if(name.equals("title")) {
+ System.out.print("书籍[" + reader.getElementText() + "]");
+ }
+ if(name.equals("price")) {
+ System.out.println("的价格为[" + reader.getElementText() + "]");
+ }
+ }
+ iteratorNum++;
+ }
+ is.close();
+ System.out.println("本次操作遍历XML的次数合计为[" + iteratorNum + "]次");
+ }
+
+
+ /**
+ * 基于Filter的方式解析XML
+ * @see 可以有效的过滤掉不用进行操作的节点,效率会高一些
+ */
+ @Test
+ public void filterParseXML() throws Exception {
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ InputStream is = ClassLoader.getSystemResourceAsStream("books.xml");
+ XMLEventReader reader = factory.createFilteredReader(factory.createXMLEventReader(is),
+ new EventFilter() {
+ @Override
+ public boolean accept(XMLEvent event) {
+ if(event.isStartElement()) {
+ String name = event.asStartElement().getName().toString();
+ if(name.equals("title") || name.equals("price")){
+ return true; //返回true表示会显示,false表示不显示
+ }
+ }
+ return false;
+ }
+ });
+ int iteratorNum = 0; //统计遍历的次数
+ while(reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ if(event.isStartElement()) {
+ String name = event.asStartElement().getName().toString();
+ if(name.equals("title")) {
+ System.out.print("书籍[" + reader.getElementText() + "]");
+ }
+ if(name.equals("price")) {
+ System.out.println("的价格为[" + reader.getElementText() + "]");
+ }
+ }
+ iteratorNum++;
+ }
+ is.close();
+ System.out.println("本次操作遍历XML的次数合计为[" + iteratorNum + "]次");
+ }
+
+
+ /**
+ * 基于XPath的方式解析XML
+ */
+ @Test
+ public void xpathParseXML() throws Exception {
+ InputStream is = ClassLoader.getSystemResourceAsStream("books.xml");
+ //创建文档处理对象
+ DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ //通过DocumentBuilder创建doc的文档对象
+ Document doc = db.parse(is);
+ //创建XPath
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ //第一个参数就是XPath表达式,第二参数就是文档..这里是查找所有属性为category="WEB"的节点
+ NodeList list = (NodeList)xpath.evaluate("//book[@category='WEB']", doc, XPathConstants.NODESET);
+ for(int i=0; i节点下只会有一个节点,所有这里是item(0)
+ System.out.println(e.getElementsByTagName("title").item(0).getTextContent());
+ System.out.println(e.getElementsByTagName("price").item(0).getTextContent());
+ }
+ is.close();
+ }
+
+
+ /**
+ * 使用XMLStreamWriter创建XML
+ */
+ @Test
+ public void xmlStreamWriterXML() throws XMLStreamException, FactoryConfigurationError {
+ XMLStreamWriter xsw = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
+ xsw.writeStartDocument("GBK","1.0");
+
+ String namespaceURI = "http://blog.csdn.net/jadyer";
+ xsw.writeStartElement("pre", "uesr", namespaceURI); //再写
+ xsw.writeStartElement("pre", "id", namespaceURI); //再写
+ xsw.writeCharacters("1"); //再写1
+ xsw.writeEndElement(); //再写
+
+ xsw.writeStartElement("pre", "name", namespaceURI); //再写
+ xsw.writeCharacters("admin"); //再写admin
+ xsw.writeEndElement();
+
+
+ xsw.writeStartElement("pre", "age", namespaceURI); //再写
+ xsw.writeCharacters("18"); //再写18
+ xsw.writeEndElement();
+
+
+ xsw.writeEndElement(); //再写
+
+ xsw.writeEndDocument(); //先写
+
+ xsw.flush();
+ xsw.close();
+ }
+
+
+ /**
+ * 使用Transformer更新XML
+ */
+ @Test
+ public void transformerModifyXML() throws Exception, TransformerFactoryConfigurationError {
+ InputStream is = ClassLoader.getSystemResourceAsStream("books.xml");
+ DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = db.parse(is);
+ XPath xpath = XPathFactory.newInstance().newXPath();
+ //查找内容含title="Learning XML"的节点
+ NodeList list = (NodeList)xpath.evaluate("//book[title='Learning XML']", doc, XPathConstants.NODESET);
+ //获取节点,这里只有一个符合条件的节点,所以写成了list.item(0)
+ Element e = (Element)(((Element)list.item(0)).getElementsByTagName("price").item(0));
+ e.setTextContent("333.9");
+ Transformer tran = TransformerFactory.newInstance().newTransformer();
+ tran.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ tran.setOutputProperty(OutputKeys.INDENT, "yes"); //让与节点之间换行,默认不换行
+ //修改节点
+ tran.transform(new DOMSource(doc), new StreamResult(System.out));
+ is.close();
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/xml-tutorials/xml-stax-example/src/main/resources/books.xml b/xml-tutorials/xml-stax-example/src/main/resources/books.xml
new file mode 100644
index 0000000..dbd4630
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/resources/books.xml
@@ -0,0 +1,31 @@
+
+
+
+ Everyday Italian
+ Giada De Laurentiis
+ 2005
+ 30.00
+
+
+ Harry Potter
+ J K. Rowling
+ 2005
+ 29.99
+
+
+ XQuery Kick Start
+ James McGovern
+ Per Bothner
+ Kurt Cagle
+ James Linn
+ Vaidyanathan Nagarajan
+ 2003
+ 49.99
+
+
+ Learning XML
+ Erik T. Ray
+ 2003
+ 39.95
+
+
\ No newline at end of file
diff --git a/xml-tutorials/xml-stax-example/src/main/resources/config.xml b/xml-tutorials/xml-stax-example/src/main/resources/config.xml
new file mode 100644
index 0000000..f19fd75
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/resources/config.xml
@@ -0,0 +1,21 @@
+
+
+
-
+ 1
+ 900
+ 1
+ 1
+
+ -
+ 2
+ 400
+ 2
+ 5
+
+ -
+ 9
+ 5
+ 100
+ 3
+
+
\ No newline at end of file
diff --git a/xml-tutorials/xml-stax-example/src/main/resources/person.xml b/xml-tutorials/xml-stax-example/src/main/resources/person.xml
new file mode 100644
index 0000000..f3499b7
--- /dev/null
+++ b/xml-tutorials/xml-stax-example/src/main/resources/person.xml
@@ -0,0 +1,28 @@
+
+
+
+ Lars
+ Vogel
+ Heidelberg
+
+
+ Jim
+ Knopf
+ Heidelberg
+
+
+ Lars
+ Strangelastname
+ London
+
+
+ Landerman
+ Petrelli
+ Somewhere
+
+
+ Lars
+ Tim
+ SomewhereElse
+
+
\ No newline at end of file