juplo:variables parses its parameter as JSON and can merge variable-defs
authorKai Moritz <kai@juplo.de>
Thu, 7 Jul 2016 11:42:56 +0000 (13:42 +0200)
committerKai Moritz <kai@juplo.de>
Mon, 18 Jul 2016 15:07:00 +0000 (17:07 +0200)
 * If the parameter can be interpreted as valid JSON, juplo:variables uses
   it directly as input.
 * The parameter accepts special keywords, that controll, if variables, that
   have been imported earlier, by a call to juplo:variables from an
   ancestor-tag, will be merged or simply overwritten.

pom.xml
src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java
src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java [new file with mode: 0644]
src/test/resources/json/1.json [new file with mode: 0644]
src/test/resources/json/2.json [new file with mode: 0644]
src/test/resources/json/3.json [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 6daf99a..a21a807 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -9,6 +9,8 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <java.version>1.8</java.version>
+    <junit.version>4.12</junit.version>
+    <logback.version>1.1.7</logback.version>
     <simple-mapper.version>1.0.0</simple-mapper.version>
     <thymeleaf.version>2.1.5.RELEASE</thymeleaf.version>
   </properties>
       <version>${simple-mapper.version}</version>
     </dependency>
 
+    <!-- Testing -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>${logback.version}</version>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
   <build>
index f679591..e864ab1 100644 (file)
@@ -5,9 +5,14 @@ import com.fasterxml.jackson.core.JsonFactory;
 import de.juplo.jackson.SimpleMapper;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.thymeleaf.Arguments;
@@ -16,6 +21,7 @@ import org.thymeleaf.TemplateProcessingParameters;
 import org.thymeleaf.context.IContext;
 import org.thymeleaf.context.VariablesMap;
 import org.thymeleaf.dom.Element;
+import org.thymeleaf.dom.Node;
 import org.thymeleaf.processor.ProcessorResult;
 import org.thymeleaf.processor.attr.AbstractAttrProcessor;
 import org.thymeleaf.resourceresolver.IResourceResolver;
@@ -31,11 +37,18 @@ import org.thymeleaf.templateresolver.TemplateResolution;
  */
 public class ImportVariablesAttrProcessor extends AbstractAttrProcessor
 {
-  public static final int ATTR_PRECEDENCE = 200;
-
   private static final Logger LOG =
       LoggerFactory.getLogger(ImportVariablesAttrProcessor.class);
   private static final JsonFactory FACTORY = new JsonFactory();
+  private static final String PROPERTY_NAME =
+      ImportVariablesAttrProcessor.class.getCanonicalName() + "_VARIABLES";
+
+  public static final Pattern PATTERN =
+      Pattern.compile(
+          "^\\s*(?:(?:(merge)|replace):)?\\s*(?:(\\{.*\\})|(.*))\\s*$",
+          Pattern.DOTALL | Pattern.CASE_INSENSITIVE
+          );
+  public static final int ATTR_PRECEDENCE = 200;
 
 
   public ImportVariablesAttrProcessor()
@@ -52,73 +65,225 @@ public class ImportVariablesAttrProcessor extends AbstractAttrProcessor
       )
   {
     Configuration config = arguments.getConfiguration();
-    String templateName = element.getAttributeValue(name);
+    String parameter = element.getAttributeValue(name);
 
-    TemplateProcessingParameters params =
-        new TemplateProcessingParameters(
-            config,
-            templateName,
-            new IContext() // << We will not execute the template, hence we need no context
-            {
-              @Override
-              public VariablesMap<String, Object> getVariables()
-              {
-                return new VariablesMap<>();
-              }
+    Iterator<Entry<String, Object>> it = null;
 
-              @Override
-              public Locale getLocale()
-              {
-                return Locale.getDefault();
-              }
+    Matcher matcher = PATTERN.matcher(parameter);
+    boolean merge = false;
+    String json = null;
+    String resource = parameter;
 
-              @Override
-              public void addContextExecutionInfo(String templateName)
-              {
-              }
-            });
-
-    for (ITemplateResolver t_resolver : config.getTemplateResolvers())
+    if (matcher.matches())
     {
-      TemplateResolution resolution = t_resolver.resolveTemplate(params);
-      if (resolution == null)
-        continue;
-      if (!"JSON".equals(resolution.getTemplateMode()))
-        continue;
-      IResourceResolver r_resolver = resolution.getResourceResolver();
-      InputStream is =
-          r_resolver.getResourceAsStream(params, resolution.getResourceName());
-      if (is == null)
-        continue;
+      merge = matcher.group(1) != null;
+      json = matcher.group(2);
+      resource = matcher.group(3);
+    }
 
+    if (json != null)
+    {
+      LOG.info("parsing parameter as JSON");
+      LOG.debug("parameter: {}", json);
       try
       {
-        Iterator<Entry<String, Object>> it =
-            SimpleMapper.getObjectIterator(FACTORY.createParser(is));
-        while(it.hasNext())
-        {
-          Entry<String, Object> entry = it.next();
-          element.setNodeLocalVariable(entry.getKey(), entry.getValue());
-        }
+        it = SimpleMapper.getObjectIterator(FACTORY.createParser(json));
       }
       catch (IOException e)
       {
-        LOG.error("cannot retreive {} as JSON: {}", templateName, e.getMessage());
+        LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage());
         throw new RuntimeException(e);
       }
-      catch (IllegalArgumentException e)
+    }
+    else
+    {
+      LOG.info("retriving {} as JSON-template", resource);
+      TemplateProcessingParameters params =
+          new TemplateProcessingParameters(
+              config,
+              resource,
+              new IContext() // << We will not execute the template, hence we need no context
+              {
+                @Override
+                public VariablesMap<String, Object> getVariables()
+                {
+                  return new VariablesMap<>();
+                }
+
+                @Override
+                public Locale getLocale()
+                {
+                  return Locale.getDefault();
+                }
+
+                @Override
+                public void addContextExecutionInfo(String templateName)
+                {
+                }
+              });
+
+      for (ITemplateResolver t_resolver : config.getTemplateResolvers())
       {
-        LOG.error("cannot parse {} as JSON: {}", templateName, e.getMessage());
-        throw new RuntimeException(e);
+        TemplateResolution resolution = t_resolver.resolveTemplate(params);
+        if (resolution == null)
+          continue;
+        if (!"JSON".equals(resolution.getTemplateMode()))
+          continue;
+        IResourceResolver r_resolver = resolution.getResourceResolver();
+        InputStream is =
+            r_resolver.getResourceAsStream(params, resolution.getResourceName());
+        if (is == null)
+          continue;
+
+        try
+        {
+          it = SimpleMapper.getObjectIterator(FACTORY.createParser(is));
+          break;
+        }
+        catch (IOException | IllegalArgumentException e)
+        {
+          LOG.error("cannot retreive {} as JSON: {}", parameter, e.getMessage());
+          throw new RuntimeException(e);
+        }
+      }
+
+      if (it == null)
+      {
+        LOG.error("cannot resolve {} as JSON (not found)!", parameter);
+        throw new RuntimeException("Template not found: " + parameter);
       }
     }
 
+    try
+    {
+      Map<String, Object> variables = getVariables(element);
+      if (merge)
+      {
+        while(it.hasNext())
+        {
+          Entry<String, Object> variable = it.next();
+          String key = variable.getKey();
+          Object value = variable.getValue();
+          Object existing = variables.get(key);
+          if (existing != null)
+          {
+            if (value instanceof String)
+            {
+              if (!(existing instanceof String))
+              {
+                LOG.error(
+                    "cannot merge variable {} of type {} with a string",
+                    key,
+                    existing.getClass()
+                    );
+                throw new RuntimeException(
+                    "Type-Missmatch for variable  " + key
+                    );
+              }
+
+              String string = ((String)existing).concat((String) value);
+              LOG.info("appending variable to string {}", key);
+              element.setNodeLocalVariable(key, string);
+            }
+            else if (value instanceof Map)
+            {
+              if (!(existing instanceof Map))
+              {
+                LOG.error(
+                    "cannot merge variable {} of type {} with a map",
+                    key,
+                    existing.getClass()
+                    );
+                throw new RuntimeException(
+                    "Type-Missmatch for variable  " + key
+                    );
+              }
+
+              Map map = ((Map)existing);
+              map.putAll((Map) value);
+              LOG.info("merging variable with map {}", key);
+              element.setNodeLocalVariable(key, map);
+            }
+            else if (value instanceof List)
+            {
+              if (!(existing instanceof List))
+              {
+                LOG.error(
+                    "cannot merge variable {} of type {} with a list",
+                    key,
+                    existing.getClass()
+                    );
+                throw new RuntimeException(
+                    "Type-Missmatch for variable  " + key
+                    );
+              }
+
+              List list = ((List)existing);
+              list.addAll((List) value);
+              LOG.info("appending contents of variable to list {}", key);
+              element.setNodeLocalVariable(key, list);
+            }
+            else
+            {
+              LOG.error(
+                  "variable {} is of unexpected type {}", key, value.getClass()
+                  );
+              throw new RuntimeException(
+                  "Found variable of unexpected type: " + key
+                  );
+            }
+          }
+          else
+          {
+            LOG.info("adding new variable {}", key);
+            element.setNodeLocalVariable(key, value);
+          }
+        }
+      }
+      else
+        while(it.hasNext())
+        {
+          Entry<String, Object> variable = it.next();
+          String key = variable.getKey();
+          Object value = variable.getValue();
+          LOG.info("adding variable {}", key);
+          variables.put(key, value);
+          element.setNodeLocalVariable(key, value);
+        }
+    }
+    catch (IllegalArgumentException e)
+    {
+      LOG.error("cannot parse {} as JSON: {}", parameter, e.getMessage());
+      throw new RuntimeException(e);
+    }
+
     element.removeAttribute(name);
 
     return ProcessorResult.OK;
   }
 
 
+  Map<String, Object> getVariables(Node node)
+  {
+    Node parent = node;
+    do
+    {
+      Map<String, Object> variables =
+          (Map<String, Object>)parent.getNodeProperty(PROPERTY_NAME);
+
+      if (variables != null)
+        return variables;
+
+      parent = parent.getParent();
+    }
+    while (parent != null);
+
+    Map<String, Object> variables = new HashMap<>();
+    node.setNodeProperty(PROPERTY_NAME, variables);
+    return variables;
+  }
+
+
   @Override
   public int getPrecedence()
   {
diff --git a/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java b/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java
new file mode 100644 (file)
index 0000000..e8e188e
--- /dev/null
@@ -0,0 +1,83 @@
+package de.juplo.thymeleaf;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+
+
+
+/**
+ *
+ * @author Kai Moritz
+ */
+public class ImportVariablesAttrProcessorTest
+{
+  @Test
+  public void testPattern() throws IOException
+  {
+    Matcher matcher;
+
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("{}");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" { } ");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\t{\t}\t");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n{\n}\n");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" \t\n{ \t\n} \t\n");
+    assertTrue(matcher.matches());
+
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("{\"foo\":\"bar\",\"foobar\":{\"foo\":\"bar\"}");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" { \"foo\":\"bar\", \"foobar\": { \"foo\": \"bar\" } ");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\t{\t\"foo\":\t\"bar\"\t,\t\"foobar\":\t{\t\"foo\":\"bar\"\t}");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n{\n\"foo\":\n\"bar\"\n,\n\"foobar\":\n{\n\"foo\":\"bar\"\n}");
+    assertTrue(matcher.matches());
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n\t {\n\t \"foo\":\n\t \"bar\"\n\t ,\n\t \"foobar\":\n\t {\n\t \"foo\":\"bar\"\n\t }");
+    assertTrue(matcher.matches());
+
+    String json;
+
+    json = read("/json/1.json");
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json);
+    assertTrue(matcher.matches());
+    json = read("/json/2.json");
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json);
+    assertTrue(matcher.matches());
+    json = read("/json/3.json");
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json);
+    assertTrue(matcher.matches());
+
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("foo:bar");
+    assertTrue(matcher.matches());
+    assertNull(matcher.group(1));
+    assertNull(matcher.group(2));
+    assertEquals("foo:bar", matcher.group(3));
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("replace:foo");
+    assertTrue(matcher.matches());
+    assertNull(matcher.group(1));
+    assertNull(matcher.group(2));
+    assertEquals("foo", matcher.group(3));
+    matcher = ImportVariablesAttrProcessor.PATTERN.matcher("merge:foo");
+    assertTrue(matcher.matches());
+    assertEquals("merge", matcher.group(1));
+    assertNull(matcher.group(2));
+    assertEquals("foo", matcher.group(3));
+  }
+
+
+  String read(String resource)
+  {
+    InputStream is = getClass().getResourceAsStream(resource);
+    return new Scanner(is).useDelimiter("\\Z").next();
+  }
+}
diff --git a/src/test/resources/json/1.json b/src/test/resources/json/1.json
new file mode 100644 (file)
index 0000000..44c8c6e
--- /dev/null
@@ -0,0 +1,75 @@
+{ "sections": { "blog": "/blog.html", "projects": "/projects.html", "about": "/about.html" }, "pages": { "/index.html": { "name": "Home" }, "/blog.html": { "name": "Blog", "childs": { "/blog/article.html": "An Article", "/blog/comments.html": "Comments" }, "crumbs": [ { "uri": "/blog.html", "name": "Blog" } ] }, "/blog/article.html": { "name": "An Article", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/article.html", "name": "An Article" } ] }, "/blog/comments.html": { "name": "Comments", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/comments.html", "name": "Comments" } ] }, "/projects.html": { "name": "Projects", "childs": { "#hibernate4-maven-plugin": "Hibernate 4 Maven Plugin", "/projects/fix-swf/overview.html": "Fix SWF", "#jquery.openx": "jQuery OpenX", "/projects/html-experimente.html": "HTML-Experimente", "#accelerator": "accelerator", "/projects/typo.html": "Typography" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" } ] }, "#hibernate4-maven-plugin": { "name": "Overview", "childs": {} }, "/projects/fix-swf/overview.html": { "name": "Overview", "childs": { "/projects/fix-swf/overview.html": "Overview", "/projects/fix-swf/getting-started.html": "Getting Started", "#faq": "FAQ", "#documentation": "Documentation" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/overview.html", "name": "Overview" } ] }, "#faq": { "name": "FAQ" }, "#documentation": { "name": "Documentation" }, "#jquery.openx": { "name": "jQuery OpenX" }, "#accelerator": { "name": "Accellerator" }, "/projects/typo.html": { "name": "Typography", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/typo.html", "name": "Typography" } ] }, "/projects/html-experimente.html": { "name": "HTML-Experimente", "childs": { "/projects/html-experimente/formulare.html": "Formulare", "/projects/html-experimente/symbole.html": "Symbol-Font", "/templates/404.html": "404-Template", "/projects/html-experimente/gibts-ja-gar-nicht.html": "404-Fehlerseite", "/templates/error.html": "5xx-Template", "/projects/html-experimente/error.html": "5xx-Fehlerseite", "/projects/html-experimente/fast-leer-mit-menü.html": "Leer, mit Menü, ohne Marginal", "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": "Leer, mit Menü, mit Marginal", "/projects/html-experimente/fast-leer-kein-menü.html": "Leer, ohne Menü, ohne Marginal", "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": "Leer, ohne Menü, mit Marginal", "/projects/html-experimente/fast-leer-einspaltig.html": "Leer, einspaltig", "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": "Leer, einspaltig, mit Marginal", "/projects/html-experimente/breadcrumb.html": "Langer Breadcrumb", "/projects/html-experimente/kein-layout.html": "Alle Stylings deaktiviert", "/projects/html-experimente/basis-layout.html": "Nur das Basis-Layout", "/projects/html-experimente/druck-layout.html": "Druck-Layout", "/projects/html-experimente/tiny.html": "Layout TINY", "/projects/html-experimente/phone.html": "Layout PHONE", "/projects/html-experimente/tablet.html": "Layout TABLET", "/projects/html-experimente/seitenaufteilung.html": "Basis-Layout & Seitenaufteilung", "/projects/html-experimente/seitenkopf.html": "Basis-Layout & Seitenkopf", "/projects/html-experimente/testlab.html": "Media-Query-Test (Beispiel)" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" } ] }, "/projects/fix-swf/getting-started.html": { "name": "Getting Started", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/getting-started.html", "name": "Getting Started" } ] }, "/projects/html-experimente/formulare.html": { "name": "Formulare", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/formulare.html", "name": "Formulare" } ] }, "/projects/html-experimente/symbole.html": { "name": "Symbol-Font", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/symbole.html", "name": "Symbol-Font" } ] }, "/templates/404.html": { "name": "404-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/404.html", "name": "404-Template" } ] }, "/projects/html-experimente/gibts-ja-gar-nicht.html": { "name": "404-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/gibts-ja-gar-nicht.html", "name": "404-Fehlerseite" } ] }, "/templates/error.html": { "name": "5xx-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/error.html", "name": "5xx-Template" } ] }, "/projects/html-experimente/error.html": { "name": "5xx-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/error.html", "name": "5xx-Fehlerseite" } ]
+    },
+    "/projects/html-experimente/fast-leer-mit-menü.html": {
+      "name": "Leer, mit Menü, ohne Marginal",
+      "crumbs": [
+        { "uri": "/projects.html", "name": "Projects" },
+        { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },
+        { "uri": "/projects/html-experimente/fast-leer-mit-menü.html", "name": "Leer, mit Menü, ohne Marginal" }
+      ]
+    },
+    "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": {
+      "name": "Leer, mit Menü, mit Marginal",
+      "crumbs": [
+        { "uri": "/projects.html", "name": "Projects" },
+        { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },
+        { "uri": "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html", "name": "Leer, mit Menü, mit Marginal" }
+      ]
+    },
+    "/projects/html-experimente/fast-leer-kein-menü.html": {
+      "name": "Leer, ohne Menü, ohne Marginal",
+      "crumbs": [
+        { "uri": "/projects.html", "name": "Projects" },
+        { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },
+        { "uri": "/projects/html-experimente/fast-leer-kein-menü.html", "name": "Leer, ohne Menü, ohne Marginal" }
+      ]
+    },
+    "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": {
+      "name": "Leer, ohne Menü, mit Marginal",
+      "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html", "name": "Leer, ohne Menü, mit Marginal" } ] }, "/projects/html-experimente/fast-leer-einspaltig.html": { "name": "Leer, einspaltig", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig.html", "name": "Leer, einspaltig" } ] }, "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": { "name": "Leer, einspaltig, mit Marginal", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html", "name": "Leer, einspaltig, mit Marginal" } ] }, "/projects/html-experimente/breadcrumb.html": { "name": "Langer Breadcrumb", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/breadcrumb.html", "name": "Langer Breadcrumb" } ] }, "/projects/html-experimente/kein-layout.html": { "name": "Alle Stylings deaktiviert", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/kein-layout.html", "name": "Alle Stylings deaktiviert" } ] }, "/projects/html-experimente/basis-layout.html": { "name": "Nur das Basis-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/basis-layout.html", "name": "Nur das Basis-Layout" } ] }, "/projects/html-experimente/druck-layout.html": { "name": "Druck-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/druck-layout.html", "name": "Druck-Layout" } ] }, "/projects/html-experimente/tiny.html": { "name": "Layout TINY", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tiny.html", "name": "Layout TINY" } ] }, "/projects/html-experimente/phone.html": { "name": "Layout PHONE", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/phone.html", "name": "Layout PHONE" } ] }, "/projects/html-experimente/tablet.html": { "name": "Layout TABLET", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tablet.html", "name": "Layout TABLET" }
+      ]
+    },
+    "/projects/html-experimente/seitenaufteilung.html": {
+      "name": "Basis-Layout & Seitenaufteilung",
+      "crumbs": [
+        { "uri": "/projects.html", "name": "Projects" },
+        { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },
+        { "uri": "/projects/html-experimente/seitenaufteilung.html", "name": "Basis-Layout & Seitenaufteilung" }
+      ]
+    },
+    "/projects/html-experimente/seitenkopf.html": {
+      "name": "Basis-Layout & Seitenkopf",
+      "crumbs": [
+        { "uri": "/projects.html", "name": "Projects" },
+        { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },
+        { "uri": "/projects/html-experimente/seitenkopf.html", "name": "Basis-Layout & Seitenkopf" }
+      ]
+    }, "/projects/html-experimente/testlab.html": { "name": "Media-Query-Test (Beispiel)", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/testlab.html", "name": "Media-Query-Test (Beispiel)" } ] }, "/about.html": { "name": "About", "childs": { "/expertise.html": "Expertise", "/references.html": "References", "/impressum.html": "Impressum", "/contact.html": "Contact" }, "crumbs": [ { "uri": "/about.html", "name": "About" } ] }, "/expertise.html": { "name": "Expertise", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/expertise.html", "name": "Expertise" } ] }, "/references.html": { "name": "References", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/references.html", "name": "References" } ] }, "/impressum.html": { "name": "Impressum", "childs": { "/agb.html": "AGB", "/haftung-inhalte.html": "Haftung für Inhalte", "/haftung-links.html": "Haftung für Links", "/urheberrechte.html": "Urheberrechte", "/datenschutz.html": "Datenschutz", "/google-analytics.html": "Google Analytics" }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" } ] }, "/contact.html": { "name": "Contact", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/contact.html", "name": "Contact" } ] }, "/agb.html": { "name": "AGB", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/agb.html", "name": "AGB" } ] }, "/haftung-inhalte.html": { "name": "Haftung für Inhalte", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/haftung-inhalte.html", "name": "Haftung für Inhalte" } ] }, "/haftung-links.html": { "name": "Haftung für Links", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/haftung-links.html", "name": "Haftung für Links" }
+      ]
+    },
+    "/urheberrechte.html": {
+      "name": "Urheberrechte",
+      "crumbs": [
+        { "uri": "/about.html", "name": "About" },
+        { "uri": "/impressum.html", "name": "Impressum" },
+        { "uri": "/urheberrechte.html", "name": "Urheberrechte" }
+      ]
+    },
+    "/datenschutz.html": {
+      "name": "Datenschutz",
+      "crumbs": [
+        { "uri": "/about.html", "name": "About" },
+        { "uri": "/impressum.html", "name": "Impressum" },
+        { "uri": "/datenschutz.html", "name": "Datenschutz" }
+      ]
+    },
+    "/google-analytics.html": {
+      "name": "Google Analytics",
+      "crumbs": [
+        { "uri": "/about.html", "name": "About" },
+        { "uri": "/impressum.html", "name": "Impressum" },
+        { "uri": "/google-analytics.html", "name": "Google Analytics" }
+      ]
+    }
+  }
+}
diff --git a/src/test/resources/json/2.json b/src/test/resources/json/2.json
new file mode 100644 (file)
index 0000000..b94325a
--- /dev/null
@@ -0,0 +1 @@
+{ "sections": { "blog": "/blog.html", "projects": "/projects.html", "about": "/about.html" }, "pages": { "/index.html": { "name": "Home" }, "/blog.html": { "name": "Blog", "childs": { "/blog/article.html": "An Article", "/blog/comments.html": "Comments" }, "crumbs": [ { "uri": "/blog.html", "name": "Blog" } ] }, "/blog/article.html": { "name": "An Article", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/article.html", "name": "An Article" } ] }, "/blog/comments.html": { "name": "Comments", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/comments.html", "name": "Comments" } ] }, "/projects.html": { "name": "Projects", "childs": { "#hibernate4-maven-plugin": "Hibernate 4 Maven Plugin", "/projects/fix-swf/overview.html": "Fix SWF", "#jquery.openx": "jQuery OpenX", "/projects/html-experimente.html": "HTML-Experimente", "#accelerator": "accelerator", "/projects/typo.html": "Typography" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" } ] }, "#hibernate4-maven-plugin": { "name": "Overview", "childs": {} }, "/projects/fix-swf/overview.html": { "name": "Overview", "childs": { "/projects/fix-swf/overview.html": "Overview", "/projects/fix-swf/getting-started.html": "Getting Started", "#faq": "FAQ", "#documentation": "Documentation" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/overview.html", "name": "Overview" } ] }, "#faq": { "name": "FAQ" }, "#documentation": { "name": "Documentation" }, "#jquery.openx": { "name": "jQuery OpenX" }, "#accelerator": { "name": "Accellerator" }, "/projects/typo.html": { "name": "Typography", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/typo.html", "name": "Typography" } ] }, "/projects/html-experimente.html": { "name": "HTML-Experimente", "childs": { "/projects/html-experimente/formulare.html": "Formulare", "/projects/html-experimente/symbole.html": "Symbol-Font", "/templates/404.html": "404-Template", "/projects/html-experimente/gibts-ja-gar-nicht.html": "404-Fehlerseite", "/templates/error.html": "5xx-Template", "/projects/html-experimente/error.html": "5xx-Fehlerseite", "/projects/html-experimente/fast-leer-mit-menü.html": "Leer, mit Menü, ohne Marginal", "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": "Leer, mit Menü, mit Marginal", "/projects/html-experimente/fast-leer-kein-menü.html": "Leer, ohne Menü, ohne Marginal", "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": "Leer, ohne Menü, mit Marginal", "/projects/html-experimente/fast-leer-einspaltig.html": "Leer, einspaltig", "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": "Leer, einspaltig, mit Marginal", "/projects/html-experimente/breadcrumb.html": "Langer Breadcrumb", "/projects/html-experimente/kein-layout.html": "Alle Stylings deaktiviert", "/projects/html-experimente/basis-layout.html": "Nur das Basis-Layout", "/projects/html-experimente/druck-layout.html": "Druck-Layout", "/projects/html-experimente/tiny.html": "Layout TINY", "/projects/html-experimente/phone.html": "Layout PHONE", "/projects/html-experimente/tablet.html": "Layout TABLET", "/projects/html-experimente/seitenaufteilung.html": "Basis-Layout & Seitenaufteilung", "/projects/html-experimente/seitenkopf.html": "Basis-Layout & Seitenkopf", "/projects/html-experimente/testlab.html": "Media-Query-Test (Beispiel)" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" } ] }, "/projects/fix-swf/getting-started.html": { "name": "Getting Started", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/getting-started.html", "name": "Getting Started" } ] }, "/projects/html-experimente/formulare.html": { "name": "Formulare", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/formulare.html", "name": "Formulare" } ] }, "/projects/html-experimente/symbole.html": { "name": "Symbol-Font", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/symbole.html", "name": "Symbol-Font" } ] }, "/templates/404.html": { "name": "404-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/404.html", "name": "404-Template" } ] }, "/projects/html-experimente/gibts-ja-gar-nicht.html": { "name": "404-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/gibts-ja-gar-nicht.html", "name": "404-Fehlerseite" } ] }, "/templates/error.html": { "name": "5xx-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/error.html", "name": "5xx-Template" } ] }, "/projects/html-experimente/error.html": { "name": "5xx-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/error.html", "name": "5xx-Fehlerseite" } ]     },     "/projects/html-experimente/fast-leer-mit-menü.html": {       "name": "Leer, mit Menü, ohne Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-mit-menü.html", "name": "Leer, mit Menü, ohne Marginal" }       ]     },     "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": {       "name": "Leer, mit Menü, mit Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html", "name": "Leer, mit Menü, mit Marginal" }       ]     },     "/projects/html-experimente/fast-leer-kein-menü.html": {       "name": "Leer, ohne Menü, ohne Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-kein-menü.html", "name": "Leer, ohne Menü, ohne Marginal" }       ]     },     "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": {       "name": "Leer, ohne Menü, mit Marginal",       "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html", "name": "Leer, ohne Menü, mit Marginal" } ] }, "/projects/html-experimente/fast-leer-einspaltig.html": { "name": "Leer, einspaltig", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig.html", "name": "Leer, einspaltig" } ] }, "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": { "name": "Leer, einspaltig, mit Marginal", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html", "name": "Leer, einspaltig, mit Marginal" } ] }, "/projects/html-experimente/breadcrumb.html": { "name": "Langer Breadcrumb", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/breadcrumb.html", "name": "Langer Breadcrumb" } ] }, "/projects/html-experimente/kein-layout.html": { "name": "Alle Stylings deaktiviert", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/kein-layout.html", "name": "Alle Stylings deaktiviert" } ] }, "/projects/html-experimente/basis-layout.html": { "name": "Nur das Basis-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/basis-layout.html", "name": "Nur das Basis-Layout" } ] }, "/projects/html-experimente/druck-layout.html": { "name": "Druck-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/druck-layout.html", "name": "Druck-Layout" } ] }, "/projects/html-experimente/tiny.html": { "name": "Layout TINY", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tiny.html", "name": "Layout TINY" } ] }, "/projects/html-experimente/phone.html": { "name": "Layout PHONE", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/phone.html", "name": "Layout PHONE" } ] }, "/projects/html-experimente/tablet.html": { "name": "Layout TABLET", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tablet.html", "name": "Layout TABLET" }       ]     },     "/projects/html-experimente/seitenaufteilung.html": {       "name": "Basis-Layout & Seitenaufteilung",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/seitenaufteilung.html", "name": "Basis-Layout & Seitenaufteilung" }       ]     },     "/projects/html-experimente/seitenkopf.html": {       "name": "Basis-Layout & Seitenkopf",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/seitenkopf.html", "name": "Basis-Layout & Seitenkopf" }       ]     }, "/projects/html-experimente/testlab.html": { "name": "Media-Query-Test (Beispiel)", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/testlab.html", "name": "Media-Query-Test (Beispiel)" } ] }, "/about.html": { "name": "About", "childs": { "/expertise.html": "Expertise", "/references.html": "References", "/impressum.html": "Impressum", "/contact.html": "Contact" }, "crumbs": [ { "uri": "/about.html", "name": "About" } ] }, "/expertise.html": { "name": "Expertise", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/expertise.html", "name": "Expertise" } ] }, "/references.html": { "name": "References", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/references.html", "name": "References" } ] }, "/impressum.html": { "name": "Impressum", "childs": { "/agb.html": "AGB", "/haftung-inhalte.html": "Haftung für Inhalte", "/haftung-links.html": "Haftung für Links", "/urheberrechte.html": "Urheberrechte", "/datenschutz.html": "Datenschutz", "/google-analytics.html": "Google Analytics" }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" } ] }, "/contact.html": { "name": "Contact", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/contact.html", "name": "Contact" } ] }, "/agb.html": { "name": "AGB", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/agb.html", "name": "AGB" } ] }, "/haftung-inhalte.html": { "name": "Haftung für Inhalte", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/haftung-inhalte.html", "name": "Haftung für Inhalte" } ] }, "/haftung-links.html": { "name": "Haftung für Links", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/haftung-links.html", "name": "Haftung für Links" }       ]     },     "/urheberrechte.html": {       "name": "Urheberrechte",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/urheberrechte.html", "name": "Urheberrechte" }       ]     },     "/datenschutz.html": {       "name": "Datenschutz",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/datenschutz.html", "name": "Datenschutz" }       ]     },     "/google-analytics.html": {       "name": "Google Analytics",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/google-analytics.html", "name": "Google Analytics" }       ]     }   } }
diff --git a/src/test/resources/json/3.json b/src/test/resources/json/3.json
new file mode 100644 (file)
index 0000000..c0b809e
--- /dev/null
@@ -0,0 +1 @@
+{ "sections": { "blog": "/blog.html", "projects": "/projects.html", "about": "/about.html" }, "pages": { "/index.html": { "name": "Home" }, "/blog.html": { "name": "Blog", "childs": { "/blog/article.html": "An Article", "/blog/comments.html": "Comments" }, "crumbs": [ { "uri": "/blog.html", "name": "Blog" } ] }, "/blog/article.html": { "name": "An Article", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/article.html", "name": "An Article" } ] }, "/blog/comments.html": { "name": "Comments", "crumbs": [ { "uri": "/blog.html", "name": "Blog" }, { "uri": "/blog/comments.html", "name": "Comments" } ] }, "/projects.html": { "name": "Projects", "childs": { "#hibernate4-maven-plugin": "Hibernate 4 Maven Plugin", "/projects/fix-swf/overview.html": "Fix SWF", "#jquery.openx": "jQuery OpenX", "/projects/html-experimente.html": "HTML-Experimente", "#accelerator": "accelerator", "/projects/typo.html": "Typography" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" } ] }, "#hibernate4-maven-plugin": { "name": "Overview", "childs": {} }, "/projects/fix-swf/overview.html": { "name": "Overview", "childs": { "/projects/fix-swf/overview.html": "Overview", "/projects/fix-swf/getting-started.html": "Getting Started", "#faq": "FAQ", "#documentation": "Documentation" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/overview.html", "name": "Overview" } ] }, "#faq": { "name": "FAQ" }, "#documentation": { "name": "Documentation" }, "#jquery.openx": { "name": "jQuery OpenX" }, "#accelerator": { "name": "Accellerator" }, "/projects/typo.html": { "name": "Typography", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/typo.html", "name": "Typography" } ] }, "/projects/html-experimente.html": { "name": "HTML-Experimente", "childs": { "/projects/html-experimente/formulare.html": "Formulare", "/projects/html-experimente/symbole.html": "Symbol-Font", "/templates/404.html": "404-Template", "/projects/html-experimente/gibts-ja-gar-nicht.html": "404-Fehlerseite", "/templates/error.html": "5xx-Template", "/projects/html-experimente/error.html": "5xx-Fehlerseite", "/projects/html-experimente/fast-leer-mit-menü.html": "Leer, mit Menü, ohne Marginal", "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": "Leer, mit Menü, mit Marginal", "/projects/html-experimente/fast-leer-kein-menü.html": "Leer, ohne Menü, ohne Marginal", "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": "Leer, ohne Menü, mit Marginal", "/projects/html-experimente/fast-leer-einspaltig.html": "Leer, einspaltig", "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": "Leer, einspaltig, mit Marginal", "/projects/html-experimente/breadcrumb.html": "Langer Breadcrumb", "/projects/html-experimente/kein-layout.html": "Alle Stylings deaktiviert", "/projects/html-experimente/basis-layout.html": "Nur das Basis-Layout", "/projects/html-experimente/druck-layout.html": "Druck-Layout", "/projects/html-experimente/tiny.html": "Layout TINY", "/projects/html-experimente/phone.html": "Layout PHONE", "/projects/html-experimente/tablet.html": "Layout TABLET", "/projects/html-experimente/seitenaufteilung.html": "Basis-Layout & Seitenaufteilung", "/projects/html-experimente/seitenkopf.html": "Basis-Layout & Seitenkopf", "/projects/html-experimente/testlab.html": "Media-Query-Test (Beispiel)" }, "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" } ] }, "/projects/fix-swf/getting-started.html": { "name": "Getting Started", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/fix-swf/overview.html", "name": "Fix SWF" }, { "uri": "/projects/fix-swf/getting-started.html", "name": "Getting Started" } ] }, "/projects/html-experimente/formulare.html": { "name": "Formulare", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/formulare.html", "name": "Formulare" } ] }, "/projects/html-experimente/symbole.html": { "name": "Symbol-Font", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/symbole.html", "name": "Symbol-Font" } ] }, "/templates/404.html": { "name": "404-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/404.html", "name": "404-Template" } ] }, "/projects/html-experimente/gibts-ja-gar-nicht.html": { "name": "404-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/gibts-ja-gar-nicht.html", "name": "404-Fehlerseite" } ] }, "/templates/error.html": { "name": "5xx-Template", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/templates/error.html", "name": "5xx-Template" } ] }, "/projects/html-experimente/error.html": { "name": "5xx-Fehlerseite", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/error.html", "name": "5xx-Fehlerseite" } ]     },     "/projects/html-experimente/fast-leer-mit-menü.html": {       "name": "Leer, mit Menü, ohne Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-mit-menü.html", "name": "Leer, mit Menü, ohne Marginal" }       ]     },     "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html": {       "name": "Leer, mit Menü, mit Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-mit-menü-und-marginalinhalt.html", "name": "Leer, mit Menü, mit Marginal" }       ]     },     "/projects/html-experimente/fast-leer-kein-menü.html": {       "name": "Leer, ohne Menü, ohne Marginal",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/fast-leer-kein-menü.html", "name": "Leer, ohne Menü, ohne Marginal" }       ]     },     "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html": {       "name": "Leer, ohne Menü, mit Marginal",       "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-kein-menü-aber-marginalinhalt.html", "name": "Leer, ohne Menü, mit Marginal" } ] }, "/projects/html-experimente/fast-leer-einspaltig.html": { "name": "Leer, einspaltig", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig.html", "name": "Leer, einspaltig" } ] }, "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html": { "name": "Leer, einspaltig, mit Marginal", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/fast-leer-einspaltig-mit-marginalinhalt.html", "name": "Leer, einspaltig, mit Marginal" } ] }, "/projects/html-experimente/breadcrumb.html": { "name": "Langer Breadcrumb", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/breadcrumb.html", "name": "Langer Breadcrumb" } ] }, "/projects/html-experimente/kein-layout.html": { "name": "Alle Stylings deaktiviert", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/kein-layout.html", "name": "Alle Stylings deaktiviert" } ] }, "/projects/html-experimente/basis-layout.html": { "name": "Nur das Basis-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/basis-layout.html", "name": "Nur das Basis-Layout" } ] }, "/projects/html-experimente/druck-layout.html": { "name": "Druck-Layout", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/druck-layout.html", "name": "Druck-Layout" } ] }, "/projects/html-experimente/tiny.html": { "name": "Layout TINY", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tiny.html", "name": "Layout TINY" } ] }, "/projects/html-experimente/phone.html": { "name": "Layout PHONE", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/phone.html", "name": "Layout PHONE" } ] }, "/projects/html-experimente/tablet.html": { "name": "Layout TABLET", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/tablet.html", "name": "Layout TABLET" }       ]     },     "/projects/html-experimente/seitenaufteilung.html": {       "name": "Basis-Layout & Seitenaufteilung",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/seitenaufteilung.html", "name": "Basis-Layout & Seitenaufteilung" }       ]     },     "/projects/html-experimente/seitenkopf.html": {       "name": "Basis-Layout & Seitenkopf",       "crumbs": [         { "uri": "/projects.html", "name": "Projects" },         { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" },         { "uri": "/projects/html-experimente/seitenkopf.html", "name": "Basis-Layout & Seitenkopf" }       ]     }, "/projects/html-experimente/testlab.html": { "name": "Media-Query-Test (Beispiel)", "crumbs": [ { "uri": "/projects.html", "name": "Projects" }, { "uri": "/projects/html-experimente.html", "name": "HTML-Experimente" }, { "uri": "/projects/html-experimente/testlab.html", "name": "Media-Query-Test (Beispiel)" } ] }, "/about.html": { "name": "About", "childs": { "/expertise.html": "Expertise", "/references.html": "References", "/impressum.html": "Impressum", "/contact.html": "Contact" }, "crumbs": [ { "uri": "/about.html", "name": "About" } ] }, "/expertise.html": { "name": "Expertise", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/expertise.html", "name": "Expertise" } ] }, "/references.html": { "name": "References", "childs": { }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/references.html", "name": "References" } ] }, "/impressum.html": { "name": "Impressum", "childs": { "/agb.html": "AGB", "/haftung-inhalte.html": "Haftung für Inhalte", "/haftung-links.html": "Haftung für Links", "/urheberrechte.html": "Urheberrechte", "/datenschutz.html": "Datenschutz", "/google-analytics.html": "Google Analytics" }, "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" } ] }, "/contact.html": { "name": "Contact", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/contact.html", "name": "Contact" } ] }, "/agb.html": { "name": "AGB", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/agb.html", "name": "AGB" } ] }, "/haftung-inhalte.html": { "name": "Haftung für Inhalte", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" }, { "uri": "/haftung-inhalte.html", "name": "Haftung für Inhalte" } ] }, "/haftung-links.html": { "name": "Haftung für Links", "crumbs": [ { "uri": "/about.html", "name": "About" }, { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/haftung-links.html", "name": "Haftung für Links" }       ]     },     "/urheberrechte.html": {       "name": "Urheberrechte",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/urheberrechte.html", "name": "Urheberrechte" }       ]     },     "/datenschutz.html": {       "name": "Datenschutz",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/datenschutz.html", "name": "Datenschutz" }       ]     },     "/google-analytics.html": {       "name": "Google Analytics",       "crumbs": [         { "uri": "/about.html", "name": "About" },         { "uri": "/impressum.html", "name": "Impressum" },         { "uri": "/google-analytics.html", "name": "Google Analytics" }       ]     }   } }