This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 8b64682  SLING-8570 - Extract a generic Content Parser API from 
org.apache.sling.jcr.contentparser with pluggable implementations
8b64682 is described below

commit 8b646824a0369b68662689cf03c6536db0309a60
Author: Radu Cotescu <[email protected]>
AuthorDate: Fri Jul 12 16:33:23 2019 +0200

    SLING-8570 - Extract a generic Content Parser API from 
org.apache.sling.jcr.contentparser with pluggable implementations
    
    * extracted a test utils module, which can be used by all contentparser
    implementations
    * added a XML Content Parser implementation
---
 .../org-apache-sling-contentparser-json/pom.xml    |   6 +
 .../json/internal/JsonContentParserTest.java       |   3 +-
 .../pom.xml                                        |  59 ++++
 .../sling/contentparser/testutils}/TestUtils.java  |  12 +-
 .../testutils}/mapsupport/ContentElement.java      |   2 +-
 .../mapsupport/ContentElementHandler.java          |   2 +-
 .../testutils}/mapsupport/ContentElementImpl.java  |   2 +-
 .../pom.xml                                        |  30 +-
 .../xml/internal/XmlContentParser.java             | 224 ++++++++++++++
 .../xml/internal/XmlContentParserTest.java}        |  66 ++--
 .../src/test/resources/content-test/content.xml    | 334 +++++++++++++++++++++
 .../invalid-test/contentWithObjectList.json        |  14 +
 .../src/test/resources/invalid-test/invalid.json   |   1 +
 contentparser/pom.xml                              |  42 +++
 14 files changed, 725 insertions(+), 72 deletions(-)

diff --git a/contentparser/org-apache-sling-contentparser-json/pom.xml 
b/contentparser/org-apache-sling-contentparser-json/pom.xml
index 3fc188b..7e6dbd9 100644
--- a/contentparser/org-apache-sling-contentparser-json/pom.xml
+++ b/contentparser/org-apache-sling-contentparser-json/pom.xml
@@ -88,6 +88,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.testutils</artifactId>
+            <version>0.9.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
 
b/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
index 3099ae8..b52e934 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
+++ 
b/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
@@ -29,7 +29,8 @@ import org.apache.sling.contentparser.api.ContentParser;
 import org.apache.sling.contentparser.api.JsonParserFeature;
 import org.apache.sling.contentparser.api.ParseException;
 import org.apache.sling.contentparser.api.ParserOptions;
-import org.apache.sling.contentparser.json.internal.mapsupport.ContentElement;
+import org.apache.sling.contentparser.testutils.TestUtils;
+import org.apache.sling.contentparser.testutils.mapsupport.ContentElement;
 import org.junit.Before;
 import org.junit.Test;
 
diff --git a/contentparser/org-apache-sling-contentparser-testutils/pom.xml 
b/contentparser/org-apache-sling-contentparser-testutils/pom.xml
new file mode 100644
index 0000000..2424af1
--- /dev/null
+++ b/contentparser/org-apache-sling-contentparser-testutils/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>35</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.contentparser.testutils</artifactId>
+    <version>0.9.0-SNAPSHOT</version>
+
+    <name>Apache Sling Content Parser Test Utilities</name>
+    <description>
+        Apache Sling Content Parser Test Utilities for the Content Parser API 
implementations
+    </description>
+
+    <scm>
+        
<connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-testutils.git</connection>
+        
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-testutils.git</developerConnection>
+        
<url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-contentparser-testutils.git</url>
+        <tag>HEAD</tag>
+    </scm>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.api</artifactId>
+            <version>0.9.0-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.8</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/TestUtils.java
 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/TestUtils.java
similarity index 79%
rename from 
contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/TestUtils.java
rename to 
contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/TestUtils.java
index 0d81e36..339f8c5 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/TestUtils.java
+++ 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/TestUtils.java
@@ -16,7 +16,7 @@
  ~ specific language governing permissions and limitations
  ~ under the License.
  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.contentparser.json.internal;
+package org.apache.sling.contentparser.testutils;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
@@ -27,8 +27,8 @@ import java.nio.charset.StandardCharsets;
 
 import org.apache.sling.contentparser.api.ContentParser;
 import org.apache.sling.contentparser.api.ParserOptions;
-import org.apache.sling.contentparser.json.internal.mapsupport.ContentElement;
-import 
org.apache.sling.contentparser.json.internal.mapsupport.ContentElementHandler;
+import org.apache.sling.contentparser.testutils.mapsupport.ContentElement;
+import 
org.apache.sling.contentparser.testutils.mapsupport.ContentElementHandler;
 
 public final class TestUtils {
     
@@ -36,11 +36,11 @@ public final class TestUtils {
         // static methods only
     }
 
-    static ContentElement parse(ContentParser contentParser, File file) throws 
IOException {
+    public static ContentElement parse(ContentParser contentParser, File file) 
throws IOException {
         return parse(contentParser, new ParserOptions(), file);
     }
 
-    static ContentElement parse(ContentParser contentParser, ParserOptions 
parserOptions, File file) throws IOException {
+    public static ContentElement parse(ContentParser contentParser, 
ParserOptions parserOptions, File file) throws IOException {
         try (FileInputStream fis = new FileInputStream(file);
              BufferedInputStream bis = new BufferedInputStream(fis)) {
             ContentElementHandler handler = new ContentElementHandler();
@@ -49,7 +49,7 @@ public final class TestUtils {
         }
     }
     
-    static ContentElement parse(ContentParser contentParser, String 
jsonContent) throws IOException {
+    public static ContentElement parse(ContentParser contentParser, String 
jsonContent) throws IOException {
         try (ByteArrayInputStream is = new 
ByteArrayInputStream(jsonContent.getBytes(StandardCharsets.UTF_8))) {
             ContentElementHandler handler = new ContentElementHandler();
             contentParser.parse(handler, is, new ParserOptions());
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElement.java
 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElement.java
similarity index 96%
rename from 
contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElement.java
rename to 
contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElement.java
index 0a4457e..37bb5ad 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElement.java
+++ 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElement.java
@@ -16,7 +16,7 @@
  ~ specific language governing permissions and limitations
  ~ under the License.
  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.contentparser.json.internal.mapsupport;
+package org.apache.sling.contentparser.testutils.mapsupport;
 
 import java.util.Map;
 
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementHandler.java
 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementHandler.java
similarity index 97%
rename from 
contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementHandler.java
rename to 
contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementHandler.java
index bc21ec0..c6e3f54 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementHandler.java
+++ 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementHandler.java
@@ -16,7 +16,7 @@
  ~ specific language governing permissions and limitations
  ~ under the License.
  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.contentparser.json.internal.mapsupport;
+package org.apache.sling.contentparser.testutils.mapsupport;
 
 import java.util.Map;
 import java.util.regex.Matcher;
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementImpl.java
 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementImpl.java
similarity index 97%
rename from 
contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementImpl.java
rename to 
contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementImpl.java
index ddbf9bd..93ec66e 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/mapsupport/ContentElementImpl.java
+++ 
b/contentparser/org-apache-sling-contentparser-testutils/src/main/java/org/apache/sling/contentparser/testutils/mapsupport/ContentElementImpl.java
@@ -16,7 +16,7 @@
  ~ specific language governing permissions and limitations
  ~ under the License.
  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.contentparser.json.internal.mapsupport;
+package org.apache.sling.contentparser.testutils.mapsupport;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
diff --git a/contentparser/org-apache-sling-contentparser-json/pom.xml 
b/contentparser/org-apache-sling-contentparser-xml/pom.xml
similarity index 83%
copy from contentparser/org-apache-sling-contentparser-json/pom.xml
copy to contentparser/org-apache-sling-contentparser-xml/pom.xml
index 3fc188b..d2063ac 100644
--- a/contentparser/org-apache-sling-contentparser-json/pom.xml
+++ b/contentparser/org-apache-sling-contentparser-xml/pom.xml
@@ -27,18 +27,18 @@
         <relativePath/>
     </parent>
 
-    <artifactId>org.apache.sling.contentparser.json</artifactId>
+    <artifactId>org.apache.sling.contentparser.xml</artifactId>
     <version>0.9.0-SNAPSHOT</version>
 
-    <name>Apache Sling Content Parser for JSON</name>
+    <name>Apache Sling Content Parser for XML</name>
     <description>
-        Apache Sling Content Parser for resource trees stored in JSON files
+        Apache Sling Content Parser for resource trees stored in XML files
     </description>
 
     <scm>
-        
<connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-json.git</connection>
-        
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-json.git</developerConnection>
-        
<url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-contentparser-json.git</url>
+        
<connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-xml.git</connection>
+        
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-contentparser-xml.git</developerConnection>
+        
<url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-contentparser-xml.git</url>
         <tag>HEAD</tag>
     </scm>
 
@@ -50,12 +50,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-json_1.0_spec</artifactId>
-            <version>1.0-alpha-1</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
             <version>2.6</version>
@@ -88,6 +82,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.contentparser.testutils</artifactId>
+            <version>0.9.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
@@ -98,11 +98,5 @@
             <version>15.0</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.apache.johnzon</groupId>
-            <artifactId>johnzon-core</artifactId>
-            <version>1.0.0</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 </project>
diff --git 
a/contentparser/org-apache-sling-contentparser-xml/src/main/java/org/apache/sling/contentparser/xml/internal/XmlContentParser.java
 
b/contentparser/org-apache-sling-contentparser-xml/src/main/java/org/apache/sling/contentparser/xml/internal/XmlContentParser.java
new file mode 100644
index 0000000..5c18539
--- /dev/null
+++ 
b/contentparser/org-apache-sling-contentparser-xml/src/main/java/org/apache/sling/contentparser/xml/internal/XmlContentParser.java
@@ -0,0 +1,224 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.contentparser.xml.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.contentparser.api.ContentHandler;
+import org.apache.sling.contentparser.api.ContentParser;
+import org.apache.sling.contentparser.api.ParseException;
+import org.apache.sling.contentparser.api.ParserHelper;
+import org.apache.sling.contentparser.api.ParserOptions;
+import org.osgi.service.component.annotations.Component;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Parses XML files that contains content fragments.
+ * Instance of this class is thread-safe.
+ */
+@Component(
+        property = {
+                ContentParser.SERVICE_PROPERTY_CONTENT_TYPE + "=" + 
ContentParser.XML_CONTENT_TYPE
+        }
+)
+public final class XmlContentParser implements ContentParser {
+
+    private static final String JCR_PRIMARY_TYPE = "jcr:primaryType";
+    private final DocumentBuilderFactory documentBuilderFactory;
+
+    public XmlContentParser() {
+        documentBuilderFactory = DocumentBuilderFactory.newInstance();
+    }
+
+    @Override
+    public void parse(ContentHandler handler, InputStream is, ParserOptions 
parserOptions) throws IOException, ParseException {
+        try {
+            DocumentBuilder documentBuilder = 
documentBuilderFactory.newDocumentBuilder();
+            Document doc = documentBuilder.parse(is);
+            parse(handler, doc.getDocumentElement(), parserOptions, null);
+        } catch (ParserConfigurationException | SAXException ex) {
+            throw new ParseException("Error parsing JCR XML content.", ex);
+        }
+    }
+
+    private void parse(ContentHandler handler, Element element, ParserOptions 
parserOptions, String parentPath) {
+        // build node path
+        String path;
+        if (parentPath == null) {
+            path = "/";
+        } else {
+            String name = getChildText(element, "name");
+            if (StringUtils.isEmpty(name)) {
+                throw new ParseException("Child node without name detected 
below path " + parentPath);
+            }
+            if (parserOptions.getIgnoreResourceNames().contains(name)) {
+                return;
+            }
+            path = parentPath.endsWith("/") ? parentPath + name : parentPath + 
"/" + name;
+        }
+
+        Map<String, Object> properties = new HashMap<>();
+
+        // primary node type and mixins
+        String primaryType = getChildText(element, "primaryNodeType");
+        if (StringUtils.isNotBlank(primaryType) && 
!parserOptions.getIgnorePropertyNames().contains("jcr:primaryType")) {
+            properties.put("jcr:primaryType", primaryType);
+        }
+        String[] mixins = getChildTextArray(element, "mixinNodeType");
+        if (mixins.length > 0 && 
!parserOptions.getIgnorePropertyNames().contains("jcr:mixinTypes")) {
+            properties.put("jcr:mixinTypes", mixins);
+        }
+
+        // properties
+        List<Element> propertyElements = getChildren(element, "property");
+        for (Element propertyElement : propertyElements) {
+
+            // property name
+            String name = getChildText(propertyElement, "name");
+            if (StringUtils.isBlank(name)) {
+                throw new ParseException("Property without name detected at 
path " + path);
+            }
+            if (parserOptions.getIgnorePropertyNames().contains(name)) {
+                continue;
+            }
+
+            // property type
+            String type = getChildText(propertyElement, "type");
+            if (StringUtils.isBlank(type)) {
+                throw new ParseException("Property '" + name + "' has no type 
at path " + path);
+            }
+
+            // property value
+            Object value;
+            List<Element> valuesElements = getChildren(propertyElement, 
"values");
+            if (!valuesElements.isEmpty()) {
+                Element valuesElement = valuesElements.get(0);
+                List<Element> valueElements = getChildren(valuesElement, 
"value");
+                String[] stringValues = new String[valueElements.size()];
+                for (int i = 0; i < valueElements.size(); i++) {
+                    stringValues[i] = valueElements.get(i).getTextContent();
+                }
+                value = convertMultiValue(stringValues, type);
+            } else {
+                String stringValue = getChildText(propertyElement, "value");
+                value = convertValue(stringValue, type);
+            }
+            properties.put(name, value);
+        }
+
+        String defaultPrimaryType = parserOptions.getDefaultPrimaryType();
+        if (defaultPrimaryType != null) {
+            if (!properties.containsKey(JCR_PRIMARY_TYPE)) {
+                properties.put(JCR_PRIMARY_TYPE, defaultPrimaryType);
+            }
+        }
+        handler.resource(path, properties);
+
+        // child nodes
+        List<Element> nodeElements = getChildren(element, "node");
+        for (Element node : nodeElements) {
+            parse(handler, node, parserOptions, path);
+        }
+
+    }
+
+    private List<Element> getChildren(Element element, String childName) {
+        List<Element> result = new ArrayList<>();
+        NodeList children = element.getChildNodes();
+        int len = children.getLength();
+        for (int i = 0; i < len; i++) {
+            Node child = children.item(i);
+            if (child instanceof Element) {
+                Element childElement = (Element) child;
+                if (StringUtils.equals(childElement.getNodeName(), childName)) 
{
+                    result.add(childElement);
+                }
+            }
+        }
+        return result;
+    }
+
+    private String getChildText(Element element, String childName) {
+        List<Element> children = getChildren(element, childName);
+        if (children.isEmpty()) {
+            return null;
+        } else if (children.size() == 1) {
+            return children.get(0).getTextContent();
+        } else {
+            throw new ParseException("Found multiple elements with name '" + 
childName + "': " + children.size());
+        }
+    }
+
+    private String[] getChildTextArray(Element element, String childName) {
+        List<Element> children = getChildren(element, childName);
+        String[] result = new String[children.size()];
+        for (int i = 0; i < children.size(); i++) {
+            result[i] = children.get(i).getTextContent();
+        }
+        return result;
+    }
+
+    private Object convertValue(String value, String type) {
+        switch (type) {
+            case "String":
+            case "Name":
+            case "Path":
+            case "Reference":
+            case "WeakReference":
+            case "URI":
+                return value;
+            case "Long":
+                return Long.valueOf(value);
+            case "Double":
+                return Double.valueOf(value);
+            case "Date":
+                return ParserHelper.parseDate(value);
+            case "Boolean":
+                return Boolean.valueOf(value);
+            case "Decimal":
+                return new BigDecimal(value);
+            default:
+                throw new ParseException(String.format("Unsupported property 
type: %s.", type));
+        }
+    }
+
+    private Object convertMultiValue(String[] values, String type) {
+        Object[] result = new Object[values.length];
+        for (int i = 0; i < values.length; i++) {
+            result[i] = convertValue(values[i], type);
+        }
+        return ParserHelper.convertSingleTypeArray(result);
+    }
+
+}
diff --git 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
 
b/contentparser/org-apache-sling-contentparser-xml/src/test/java/org/apache/sling/contentparser/xml/internal/XmlContentParserTest.java
similarity index 69%
copy from 
contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
copy to 
contentparser/org-apache-sling-contentparser-xml/src/test/java/org/apache/sling/contentparser/xml/internal/XmlContentParserTest.java
index 3099ae8..111ac73 100644
--- 
a/contentparser/org-apache-sling-contentparser-json/src/test/java/org/apache/sling/contentparser/json/internal/JsonContentParserTest.java
+++ 
b/contentparser/org-apache-sling-contentparser-xml/src/test/java/org/apache/sling/contentparser/xml/internal/XmlContentParserTest.java
@@ -16,51 +16,50 @@
  ~ specific language governing permissions and limitations
  ~ under the License.
  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-package org.apache.sling.contentparser.json.internal;
+package org.apache.sling.contentparser.xml.internal;
 
 import java.io.File;
 import java.math.BigDecimal;
 import java.util.Calendar;
-import java.util.EnumSet;
 import java.util.Map;
 import java.util.TimeZone;
 
 import org.apache.sling.contentparser.api.ContentParser;
-import org.apache.sling.contentparser.api.JsonParserFeature;
 import org.apache.sling.contentparser.api.ParseException;
 import org.apache.sling.contentparser.api.ParserOptions;
-import org.apache.sling.contentparser.json.internal.mapsupport.ContentElement;
+import org.apache.sling.contentparser.testutils.mapsupport.ContentElement;
 import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableSet;
 
-import static junit.framework.TestCase.assertNull;
+import static org.apache.sling.contentparser.testutils.TestUtils.parse;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
-public class JsonContentParserTest {
+public class XmlContentParserTest {
 
     private File file;
-    private ContentParser contentParser;
+    private ContentParser underTest;
 
     @Before
     public void setUp() {
-        file = new File("src/test/resources/content-test/content.json");
-        contentParser = new JsonContentParser();
+        file = new File("src/test/resources/content-test/content.xml");
+        underTest = new XmlContentParser();
     }
 
     @Test
     public void testPageJcrPrimaryType() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, file);
+        ContentElement content = parse(underTest, file);
 
         assertEquals("app:Page", 
content.getProperties().get("jcr:primaryType"));
     }
 
     @Test
     public void testDataTypes() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, file);
+        ContentElement content = parse(underTest, file);
 
         Map<String, Object> props = 
content.getChild("toolbar/profiles/jcr:content").getProperties();
         assertEquals(true, props.get("hideInNav"));
@@ -76,7 +75,7 @@ public class JsonContentParserTest {
 
     @Test
     public void testContentProperties() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, file);
+        ContentElement content = parse(underTest, file);
 
         Map<String, Object> props = 
content.getChild("jcr:content/header").getProperties();
         assertEquals("/content/dam/sample/header.png", 
props.get("imageReference"));
@@ -84,7 +83,7 @@ public class JsonContentParserTest {
 
     @Test
     public void testCalendar() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, new 
ParserOptions().detectCalendarValues(true), file);
+        ContentElement content = parse(underTest, new 
ParserOptions().detectCalendarValues(true), file);
 
         Map<String, Object> props = 
content.getChild("jcr:content").getProperties();
 
@@ -103,26 +102,9 @@ public class JsonContentParserTest {
     }
 
     @Test
-    public void testIso8601Calendar() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, new 
ParserOptions().detectCalendarValues(true), file);
-
-        Map<String, Object> props = 
content.getChild("jcr:content").getProperties();
-
-        Calendar calendar = (Calendar) props.get("dateISO8601String");
-        assertNotNull(calendar);
-
-        assertEquals(2014, calendar.get(Calendar.YEAR));
-        assertEquals(4, calendar.get(Calendar.MONTH) + 1);
-        assertEquals(22, calendar.get(Calendar.DAY_OF_MONTH));
-
-        assertEquals(15, calendar.get(Calendar.HOUR_OF_DAY));
-        assertEquals(11, calendar.get(Calendar.MINUTE));
-        assertEquals(24, calendar.get(Calendar.SECOND));
-    }
-
-    @Test
     public void testUTF8Chars() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, file);
+
+        ContentElement content = parse(underTest, file);
 
         Map<String, Object> props = 
content.getChild("jcr:content").getProperties();
 
@@ -132,23 +114,23 @@ public class JsonContentParserTest {
     @Test(expected = ParseException.class)
     public void testParseInvalidJson() throws Exception {
         file = new File("src/test/resources/invalid-test/invalid.json");
-        ContentElement content = TestUtils.parse(contentParser, file);
+
+        ContentElement content = parse(underTest, file);
         assertNull(content);
     }
 
     @Test(expected = ParseException.class)
     public void testParseInvalidJsonWithObjectList() throws Exception {
         file = new 
File("src/test/resources/invalid-test/contentWithObjectList.json");
-        ContentElement content = TestUtils.parse(contentParser, file);
+
+        ContentElement content = parse(underTest, file);
         assertNull(content);
     }
 
     @Test
     public void testIgnoreResourcesProperties() throws Exception {
-        ContentElement content = TestUtils.parse(
-                contentParser,
-                new 
ParserOptions().ignoreResourceNames(ImmutableSet.of("header", "newslist", 
"security:acl", "security:principals"))
-                        .ignorePropertyNames(ImmutableSet.of("jcr:title")), 
file);
+        ContentElement content = parse(underTest,  new 
ParserOptions().ignoreResourceNames(ImmutableSet.of("header", "newslist"))
+                .ignorePropertyNames(ImmutableSet.of("jcr:title")), file);
         ContentElement child = content.getChild("jcr:content");
 
         assertEquals("Sample Homepage", 
child.getProperties().get("pageTitle"));
@@ -164,7 +146,8 @@ public class JsonContentParserTest {
 
     @Test
     public void testGetChild() throws Exception {
-        ContentElement content = TestUtils.parse(contentParser, file);
+
+        ContentElement content = parse(underTest, file);
         assertNull(content.getName());
 
         ContentElement deepChild = 
content.getChild("jcr:content/par/image/file/jcr:content");
@@ -178,9 +161,4 @@ public class JsonContentParserTest {
         assertNull(invalidChild);
     }
 
-    @Test(expected = ParseException.class)
-    public void testFailsWithoutCommentsEnabled() throws Exception {
-        TestUtils.parse(contentParser, new 
ParserOptions().jsonParserFeatures(EnumSet.noneOf(JsonParserFeature.class)), 
file);
-    }
-
 }
diff --git 
a/contentparser/org-apache-sling-contentparser-xml/src/test/resources/content-test/content.xml
 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/content-test/content.xml
new file mode 100644
index 0000000..6caed95
--- /dev/null
+++ 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/content-test/content.xml
@@ -0,0 +1,334 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+<node>
+  <primaryNodeType>app:Page</primaryNodeType>
+  
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+  <property><name>jcr:created</name><value>Thu Aug 07 2014 16:32:59 
GMT+0200</value><type>Date</type></property>
+  
+  <node>
+    <name>jcr:content</name>
+    <primaryNodeType>app:PageContent</primaryNodeType>
+    
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+    
<property><name>jcr:title</name><value>English</value><type>String</type></property>
+    
<property><name>app:template</name><value>sample/templates/homepage</value><type>String</type></property>
+    <property><name>jcr:created</name><value>Thu Aug 07 2014 16:32:59 
GMT+0200</value><type>Date</type></property>
+    <property><name>app:lastModified</name><value>Tue Apr 22 2014 15:11:24 
GMT+0200</value><type>Date</type></property>
+    
<property><name>dateISO8601String</name><value>2014-04-22T15:11:24.000+02:00</value><type>Date</type></property>
+    <property><name>pageTitle</name><value>Sample 
Homepage</value><type>String</type></property>
+    
<property><name>sling:resourceType</name><value>sample/components/homepage</value><type>String</type></property>
+    
<property><name>sling:resourceSuperType</name><value>sample/components/supertype</value><type>String</type></property>
+    
<property><name>app:designPath</name><value>/etc/designs/sample</value><type>String</type></property>
+    
<property><name>app:lastModifiedBy</name><value>admin</value><type>String</type></property>
+    
<property><name>utf8Property</name><value>äöü߀</value><type>String</type></property>
+    
<property><name>refpro1</name><value>abc</value><type>Reference</type></property>
+    
<property><name>pathprop1</name><value>def</value><type>Path</type></property>
+    
+    <node>
+      <name>par</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      
<property><name>sling:resourceType</name><value>foundation/components/parsys</value><type>String</type></property>
+      <node>
+        <name>colctrl</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        
<property><name>layout</name><value>2;colctrl-lt0</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:02:24 
GMT+0200</value><type>Date</type></property>
+        <property><name>jcr:lastModified</name><value>Mon Aug 23 2010 22:02:35 
GMT+0200</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/parsys/colctrl</value><type>String</type></property>
+      </node>
+      <node>
+        <name>image</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>fileReference</name><value>/content/dam/sample/portraits/jane_doe.jpg</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:03:39 
GMT+0200</value><type>Date</type></property>
+        
<property><name>width</name><value>340</value><type>String</type></property>
+        <property><name>jcr:lastModified</name><value>Sun Oct 31 2010 21:39:50 
GMT+0100</value><type>Date</type></property>
+        
<property><name>sling:resourceTyp</name><value>foundation/components/image</value><type>String</type></property>
+        <node>
+          <name>file</name>
+          <primaryNodeType>nt:file</primaryNodeType>
+          
<property><name>jcr:createdB</name><value>admin</value><type>String</type></property>
+          <property><name>jcr:created</name><value>Thu Aug 07 2014 16:32:59 
GMT+0200</value><type>Date</type></property>
+          <node>
+            <name>jcr:content</name>
+            <primaryNodeType>nt:resource</primaryNodeType>
+            
<property><name>jcr:lastModifiedBy</name><value>anonymous</value><type>String</type></property>
+            
<property><name>jcr:mimeType</name><value>image/jpeg</value><type>String</type></property>
+            <property><name>jcr:lastModified</name><value>Thu Aug 07 2014 
16:32:59 GMT+0200</value><type>Date</type></property>
+            
<property><name>jcr:uuid</name><value>eda76d00-b2cd-4b59-878f-c33f71ceaddc</value><type>String</type></property>
+          </node>
+        </node>
+      </node>
+      <node>
+        <name>title_1</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:title</name><value>Strategic 
Consulting</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:12:08 
GMT+0200</value><type>Date</type></property>
+        <property><name>jcr:lastModified</name><value>Wed Oct 27 2010 21:33:24 
GMT+0200</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>sample/components/title</value><type>String</type></property>
+      </node>
+      <node>
+        <name>text_1</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Sun Oct 31 2010 21:48:04 
GMT+0100</value><type>Date</type></property>
+        <property><name>text</name><value><![CDATA[<p><span 
class="Apple-style-span" style="font-size: 12px;">In&nbsp;today's competitive 
market, organizations can face several key geometric challenges:</span></p>
+<ul>
+<li><span class="Apple-style-span" style="font-size: 12px;">Polyhedral 
Sectioning</span></li>
+<li><span class="Apple-style-span" style="font-size: 
12px;">Triangulation&nbsp;</span></li>
+<li><span class="Apple-style-span" style="font-size: 12px;">Trigonometric 
Calculation</span></li>
+<li><span class="Apple-style-span" style="font-size: 12px;">Ruler and Compass 
Construction</span></li>
+</ul>
+<p><span class="Apple-style-span" style="font-size: 12px;"><br>
+Sample is ready to help your organization deal effectively with all these 
challenges through our award winning geometric consulting services.</span></p>
+<p style="font-family: tahoma, arial, helvetica, sans-serif; font-size: 
12px;\"><\/p>
+]]></value><type>String</type></property>
+        <property><name>jcr:lastModified</name><value>Sun Oct 31 2010 21:49:06 
GMT+0100</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/text</value><type>String</type></property>
+        
<property><name>textIsRich</name><value>true</value><type>String</type></property>
+      </node>
+      <node>
+        <name>col_break12825937554040</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>controlType</name><value>break</value><type>String</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/parsys/colctrl</value><type>String</type></property>
+      </node>
+      <node>
+        <name>image_0</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>fileReference</name><value>/content/dam/sample/offices/clean_room.jpg</value><type>String</type></property>
+        
<property><name>height</name><value>226</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:04:46 
GMT+0200</value><type>Date</type></property>
+        <property><name>jcr:lastModified</name><value>Fri Nov 05 2010 10:38:15 
GMT+0100</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/image</value><type>String</type></property>
+        
<property><name>imageRotate</name><value>0</value><type>String</type></property>
+        <node>
+          <name>file</name>
+          <primaryNodeType>nt:file</primaryNodeType>
+          
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+          <property><name>jcr:created</name><value>Thu Aug 07 2014 16:32:59 
GMT+0200</value><type>Date</type></property>
+          <node>
+            <name>jcr:content</name>
+            <primaryNodeType>nt:resource</primaryNodeType>
+            
<property><name>jcr:lastModifiedBy</name><value>anonymous</value><type>String</type></property>
+            
<property><name>jcr:mimeType</name><value>image/jpeg</value><type>String</type></property>
+            <property><name>jcr:lastModified</name><value>Thu Aug 07 2014 
16:32:59 GMT+0200</value><type>String</type></property>
+            
<property><name>jcr:uuid</name><value>6139077f-191f-4337-aaef-55456ebe6784</value><type>String</type></property>
+          </node>
+        </node>
+      </node>
+      <node>
+        <name>title_2</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:title</name><value>Shape 
Technology</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:12:13 
GMT+0200</value><type>Date</type></property>
+        <property><name>jcr:lastModified</name><value>Tue Oct 26 2010 21:16:29 
GMT+0200</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>sample/components/title</value><type>String</type></property>
+      </node>
+      <node>
+        <name>text_0</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Mon Aug 23 2010 22:16:30 
GMT+0200</value><type>Date</type></property>
+        <property><name>text</name><value><![CDATA[<p>The Sample investment in 
R&amp;D has done more than solidify our industry leadership role, we have now 
outpaced our competitors to such an extent that we are in an altogether new 
space.</p>
+<p>This is why our high quality polygons and polyhedra provide the only 
turnkey solutions across the whole range of euclidean geometry. And our 
mathematicians are working on the next generation of fractal curves to bring 
you shapes that are unthinkable today.</p>
+<p></p>
+<p></p>
+]]></value><type>String</type></property>
+        <property><name>jcr:lastModified</name><value>Mon Nov 08 2010 20:39:00 
GMT+0100</value><type>Date</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/text</value><type>String</type></property>
+        
<property><name>textIsRich</name><value>true</value><type>String</type></property>
+      </node>
+      <node>
+        <name>col_end12825937444810</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>controlType</name><value>end</value><type>String</type></property>
+        
<property><name>sling:resourceType</name><value>foundation/components/parsys/colctrl</value><type>String</type></property>
+      </node>
+    </node>
+    <node>
+      <name>header</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      <property><name>jcr:title</name><value>trust our experience
+to manage your business</value><type>String</type></property>
+      
<property><name>imageReference</name><value>/content/dam/sample/header.png</value><type>String</type></property>
+      <property><name>text</name><value>Lorem ipsum dolor sit amet, 
consectetuer adipiscing elit. Nunc eget neque. Nunc condimentum ipsum et orci. 
Aenean est. Cras eget diam. read more</value><type>String</type></property>
+      
<property><name>sling:resourceType</name><value>sample/components/header</value><type>String</type></property>
+    </node>
+    <node>
+      <name>newslist</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      <property><name>headline</name><value>trust our experience
+to manage your business</value><type>String</type></property>
+      <property><name>text</name><value>Lorem ipsum dolor sit amet, 
consectetuer adipiscing elit. Nunc eget neque. Nunc condimentum ipsum et orci. 
Aenean est. Cras eget diam. read more</value><type>String</type></property>
+      
<property><name>sling:resourceType</name><value>sample/components/listchildren</value><type>String</type></property>
+      
<property><name>listroot</name><value>/content/sample/en/about/news</value><type>String</type></property>
+    </node>
+    <node>
+      <name>lead</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      <property><name>jcr:title</name><value>World Leader in Applied Geometry 
</value><type>String</type></property>
+      
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+      <property><name>text</name><value>Lead 
Text</value><type>String</type></property>
+      <property><name>title</name><value>Lead 
Title</value><type>String</type></property>
+      <property><name>jcr:description</name><value>ample has been selling and 
servicing shapes for over 2000 years. From our beginnings as a small vendor of 
squares and rectangles we have grown our business into a leading global 
provider of platonic solids and fractals. Join us as we lead geometry into the 
future.</value><type>String</type></property>
+      <property><name>jcr:lastModified</name><value>Wed Jan 19 2011 14:35:29 
GMT+0100</value><type>Date</type></property>
+      
<property><name>sling:resourceType</name><value>sample/components/lead</value><type>String</type></property>
+      <node>
+        <name>app:annotations</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+      </node>
+    </node>
+    <node>
+      <name>image</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+      <property><name>jcr:lastModified</name><value>Wed Oct 27 2010 21:30:59 
GMT+0200</value><type>Date</type></property>
+      
<property><name>imageRotate</name><value>0</value><type>String</type></property>
+    </node>
+    <node>
+      <name>carousel</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      
<property><name>playSpeed</name><value>6000</value><type>String</type></property>
+      
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+      
<property><name>pages</name><values><value>/content/sample/en/events/techsummit</value><value>/content/sample/en/events/userconf</value><value>/content/sample/en/events/shapecon</value><value>/content/sample/en/events/dsc</value></values><type>String</type></property>
+      <property><name>jcr:lastModified</name><value>Tue Oct 05 2010 14:14:27 
GMT+0200</value><type>Date</type></property>
+      
<property><name>transTime</name><value>1000</value><type>String</type></property>
+      
<property><name>sling:resourceType</name><value>foundation/components/carousel</value><type>String</type></property>
+      
<property><name>listFrom</name><value>static</value><type>String</type></property>
+    </node>
+    <node>
+      <name>rightpar</name>
+      <primaryNodeType>nt:unstructured</primaryNodeType>
+      
<property><name>sling:resourceType</name><value>foundation/components/parsys</value><type>String</type></property>
+      <node>
+        <name>teaser</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>jcr:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Tue Jan 25 2011 11:30:09 
GMT+0100</value><type>Date</type></property>
+        
<property><name>campaignpath</name><value>/content/campaigns/sample</value><type>String</type></property>
+        <property><name>jcr:lastModified</name><value>Wed Feb 02 2011 08:40:30 
GMT+0100</value><type>Date</type></property>
+        
<property><name>sling:resourceTyp</name><value>personalization/components/teaser</value><type>String</type></property>
+      </node>
+    </node>
+  </node>
+  <node>
+    <name>toolbar</name>
+    <primaryNodeType>app:Page</primaryNodeType>
+    
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+    <property><name>jcr:created</name><value>Thu Aug 07 2014 16:33:00 
GMT+0200</value><type>String</type></property>
+    <node>
+      <name>jcr:content</name>
+      <primaryNodeType>app:PageContent</primaryNodeType>
+      <property><name>subtitle</name><value>Contains the 
toolbar</value><type>String</type></property>
+      
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+      
<property><name>jcr:title</name><value>Toolbar</value><type>String</type></property>
+      
<property><name>app:template</name><value>sample/templates/contentpage</value><type>String</type></property>
+      <property><name>jcr:created</name><value>Thu Aug 07 2014 16:33:00 
GMT+0200</value><type>String</type></property>
+      <property><name>app:lastModified</name><value>Wed Aug 25 2010 22:51:02 
GMT+0200</value><type>Date</type></property>
+      
<property><name>hideInNav</name><value>true</value><type>Date</type></property>
+      
<property><name>sling:resourceType</name><value>sample/components/contentpage</value><type>String</type></property>
+      
<property><name>app:lastModifiedBy</name><value>admin</value><type>String</type></property>
+      <node>
+        <name>par</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>sling:resourceType</name><value>foundation/components/parsys</value><type>String</type></property>
+      </node>
+      <node>
+        <name>rightpar</name>
+        <primaryNodeType>nt:unstructured</primaryNodeType>
+        
<property><name>sling:resourceType</name><value>foundation/components/iparsys</value><type>String</type></property>
+        <node>
+          <name>iparsys_fake_par</name>
+          <primaryNodeType>nt:unstructured</primaryNodeType>
+          
<property><name>sling:resourceType</name><value>foundation/components/iparsys/par</value><type>String</type></property>
+        </node>
+      </node>
+    </node>
+    <node>
+      <name>profiles</name>
+      <primaryNodeType>app:Page</primaryNodeType>
+      
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+      <property><name>jcr:created</name><value>Thu Aug 07 2014 16:33:00 
GMT+0200</value><type>Date</type></property>
+      <node>
+        <name>jcr:content</name>
+        <primaryNodeType>app:PageContent</primaryNodeType>
+        <mixinNodeType>type1</mixinNodeType>
+        <mixinNodeType>type2</mixinNodeType>
+        
<property><name>jcr:createdBy</name><value>admin</value><type>String</type></property>
+        
<property><name>jcr:title</name><value>Profiles</value><type>String</type></property>
+        
<property><name>app:template</name><value>sample/templates/contentpage</value><type>String</type></property>
+        <property><name>jcr:created</name><value>Thu Aug 07 2014 16:33:00 
GMT+0200</value><type>Date</type></property>
+        <property><name>app:lastModified</name><value>Thu Nov 05 2009 20:27:13 
GMT+0100</value><type>Date</type></property>
+        
<property><name>hideInNav</name><value>true</value><type>Boolean</type></property>
+        
<property><name>sling:resourceType</name><value>sample/components/contentpage</value><type>String</type></property>
+        
<property><name>app:lastModifiedBy</name><value>admin</value><type>String</type></property>
+        
<property><name>longProp</name><value>1234567890123</value><type>Long</type></property>
+        
<property><name>decimalProp</name><value>1.2345</value><type>Decimal</type></property>
+        
<property><name>booleanProp</name><value>true</value><type>Boolean</type></property>
+        
<property><name>longPropMulti</name><values><value>1234567890123</value><value>55</value></values><type>Long</type></property>
+        
<property><name>decimalPropMulti</name><values><value>1.2345</value><value>1.1</value></values><type>Decimal</type></property>
+        
<property><name>booleanPropMulti</name><values><value>true</value><value>false</value></values><type>Boolean</type></property>
+        
<property><name>stringPropMulti</name><values><value>aa</value><value>bb</value><value>cc</value></values><type>String</type></property>
+        <node>
+          <name>par</name>
+          <primaryNodeType>nt:unstructured</primaryNodeType>
+          
<property><name>sling:resourceType</name><value>foundation/components/parsys</value><type>String</type></property>
+          <node>
+            <name>textimage</name>
+            <primaryNodeType>nt:unstructured</primaryNodeType>
+            
<property><name>sling:resourceType</name><value>foundation/components/textimage</value><type>String</type></property>
+          </node>
+          <node>
+            <name>mygadgets</name>
+            <primaryNodeType>nt:unstructured</primaryNodeType>
+            
<property><name>gadgets</name><value>http://customer.meteogroup.de/meteogroup/gadgets/wetter24.xml
+http://germanweatherradar.googlecode.com/svn/trunk/german-weather-radar.xml
+http://www.digitalpowered.info/gadget/ski.pictures.xml
+http://www.canbuffi.de/gadgets/clock/clock.xml</value><type>String</type></property>
+            
<property><name>sling:resourceType</name><value>personalization/components/mygadgets</value><type>String</type></property>
+          </node>
+        </node>
+        <node>
+          <name>rightpar</name>
+          <primaryNodeType>nt:unstructured</primaryNodeType>
+          
<property><name>sling:resourceType</name><value>foundation/components/iparsys</value><type>String</type></property>
+          <node>
+            <name>iparsys_fake_par</name>
+            <primaryNodeType>nt:unstructured</primaryNodeType>
+            
<property><name>sling:resourceType</name><value>foundation/components/iparsys/par</value><type>String</type></property>
+          </node>
+        </node>
+      </node>
+    </node>
+  </node>
+</node>
diff --git 
a/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/contentWithObjectList.json
 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/contentWithObjectList.json
new file mode 100644
index 0000000..e4527a0
--- /dev/null
+++ 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/contentWithObjectList.json
@@ -0,0 +1,14 @@
+{
+  "prop1": "value1",
+  "childObject": {
+    "prop2": "value2"
+  },
+  "childObjectList": [
+    {
+      "prop1": "value1"
+    },
+    {
+      "prop2": "value2"
+    }
+  ]
+}
diff --git 
a/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/invalid.json
 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/invalid.json
new file mode 100644
index 0000000..59fc86c
--- /dev/null
+++ 
b/contentparser/org-apache-sling-contentparser-xml/src/test/resources/invalid-test/invalid.json
@@ -0,0 +1 @@
+This is invalid json.
diff --git a/contentparser/pom.xml b/contentparser/pom.xml
new file mode 100644
index 0000000..9b5dd03
--- /dev/null
+++ b/contentparser/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+    
+    http://www.apache.org/licenses/LICENSE-2.0
+    
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>35</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.contentparser.reactor</artifactId>
+    <packaging>pom</packaging>
+    <version>0.9.0-SNAPSHOT</version>
+
+    <name>Apache Sling Content Parser Reactor</name>
+
+    <modules>
+        <module>org-apache-sling-contentparser-api</module>
+        <module>org-apache-sling-contentparser-json</module>
+        <module>org-apache-sling-contentparser-xml</module>
+        <module>org-apache-sling-contentparser-testutils</module>
+    </modules>
+</project>

Reply via email to