From 3b77333b1046ea6d9536a63f218323ed56ccfaf2 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sat, 31 Oct 2020 12:22:21 +0100 Subject: [PATCH] Can write properties as attributes in toXmlElements. --- org.argeo.jcr/src/org/argeo/jcr/Jcr.java | 13 +- .../src/org/argeo/jcr/xml/JcrXmlUtils.java | 134 +++++++++++++----- 2 files changed, 107 insertions(+), 40 deletions(-) diff --git a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java index 5ce8017ca..fe73b53f4 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/Jcr.java +++ b/org.argeo.jcr/src/org/argeo/jcr/Jcr.java @@ -36,19 +36,26 @@ import javax.jcr.version.VersionManager; * exceptions. Loosely inspired by Java's Files singleton. */ public class Jcr { - + /** + * The name of a node which will be serialized as XML text, as per section 7.3.1 + * of the JCR 2.0 specifications. + */ + public final static String JCR_XMLTEXT = "jcr:xmltext"; + /** + * The name of a property which will be serialized as XML text, as per section + * 7.3.1 of the JCR 2.0 specifications. + */ + public final static String JCR_XMLCHARACTERS = "jcr:xmlcharacters"; /** * jcr:name, when used in another context than * {@link Property#JCR_NAME}, typically to name a node rather than a property. */ public final static String JCR_NAME = "jcr:name"; - /** * jcr:path, when used in another context than * {@link Property#JCR_PATH}, typically to name a node rather than a property. */ public final static String JCR_PATH = "jcr:path"; - /** * jcr:primaryType with prefix instead of namespace (as in * {@link Property#JCR_PRIMARY_TYPE}. diff --git a/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java b/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java index 6f1a92260..2adb6a97e 100644 --- a/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java +++ b/org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java @@ -2,6 +2,8 @@ package org.argeo.jcr.xml; import java.io.IOException; import java.io.Writer; +import java.util.Map; +import java.util.TreeMap; import javax.jcr.Node; import javax.jcr.NodeIterator; @@ -20,31 +22,66 @@ public class JcrXmlUtils { * false. */ public static void toXmlElements(Writer writer, Node node) throws RepositoryException, IOException { - toXmlElements(writer, node, false, false); + toXmlElements(writer, node, null, false, false, false); } /** * Write JCR properties as XML elements in a tree structure whose elements are * named by node primary type. * - * @param writer the writer to use - * @param node the subtree - * @param withMetadata whether to write the primary type and mixins as elements - * jcr:primaryType ( + * @param writer the writer to use + * @param node the subtree + * @param depth maximal depth, or if null the whole + * subtree. It must be positive, with depth 0 + * describing just the node without its children. + * @param withMetadata whether to write the primary type and mixins as + * elements + * @param withPrefix whether to keep the namespace prefixes + * @param propertiesAsElements whether single properties should be written as + * elements rather than attributes. If + * false, multiple properties will be + * skipped. */ - public static void toXmlElements(Writer writer, Node node, boolean withMetadata, boolean withPrefix) - throws RepositoryException, IOException { - if (withMetadata && node.hasProperty(Property.JCR_UUID)) { - writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix), "id", - "urn:uuid:" + node.getProperty(Property.JCR_UUID).getString()); - } else { - writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); + public static void toXmlElements(Writer writer, Node node, Integer depth, boolean withMetadata, boolean withPrefix, + boolean propertiesAsElements) throws RepositoryException, IOException { + if (depth != null && depth < 0) + throw new IllegalArgumentException("Depth " + depth + " is negative."); + + if (node.getName().equals(Jcr.JCR_XMLTEXT)) { + writer.write(node.getProperty(Jcr.JCR_XMLCHARACTERS).getString()); + return; } - // name - writeStart(writer, withPrefix ? Jcr.JCR_NAME : "name"); - writer.append(node.getName()); - writeEnd(writer, withPrefix ? Jcr.JCR_NAME : "name"); + if (!propertiesAsElements) { + Map attrs = new TreeMap<>(); + PropertyIterator pit = node.getProperties(); + properties: while (pit.hasNext()) { + Property p = pit.nextProperty(); + if (!p.isMultiple()) { + String pName = p.getName(); + if (!withMetadata && (pName.equals(Jcr.JCR_PRIMARY_TYPE) || pName.equals(Jcr.JCR_UUID) + || pName.equals(Jcr.JCR_CREATED) || pName.equals(Jcr.JCR_CREATED_BY) + || pName.equals(Jcr.JCR_LAST_MODIFIED) || pName.equals(Jcr.JCR_LAST_MODIFIED_BY))) + continue properties; + attrs.put(withPrefix(p.getName(), withPrefix), p.getString()); + } + } + if (withMetadata && node.hasProperty(Property.JCR_UUID)) + attrs.put("id", "urn:uuid:" + node.getProperty(Property.JCR_UUID).getString()); + attrs.put(withPrefix ? Jcr.JCR_NAME : "name", node.getName()); + writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix), attrs, node.hasNodes()); + } else { + if (withMetadata && node.hasProperty(Property.JCR_UUID)) { + writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix), "id", + "urn:uuid:" + node.getProperty(Property.JCR_UUID).getString()); + } else { + writeStart(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); + } + // name + writeStart(writer, withPrefix ? Jcr.JCR_NAME : "name"); + writer.append(node.getName()); + writeEnd(writer, withPrefix ? Jcr.JCR_NAME : "name"); + } // mixins if (withMetadata) { @@ -55,36 +92,42 @@ public class JcrXmlUtils { } } - // properties - PropertyIterator pit = node.getProperties(); - properties: while (pit.hasNext()) { - Property p = pit.nextProperty(); - if (p.isMultiple()) { - for (Value value : p.getValues()) { + // properties as elements + if (propertiesAsElements) { + PropertyIterator pit = node.getProperties(); + properties: while (pit.hasNext()) { + Property p = pit.nextProperty(); + if (p.isMultiple()) { + for (Value value : p.getValues()) { + writeStart(writer, withPrefix(p.getName(), withPrefix)); + writer.write(value.getString()); + writeEnd(writer, withPrefix(p.getName(), withPrefix)); + } + } else { + Value value = p.getValue(); + String pName = p.getName(); + if (!withMetadata && (pName.equals(Jcr.JCR_PRIMARY_TYPE) || pName.equals(Jcr.JCR_UUID) + || pName.equals(Jcr.JCR_CREATED) || pName.equals(Jcr.JCR_CREATED_BY) + || pName.equals(Jcr.JCR_LAST_MODIFIED) || pName.equals(Jcr.JCR_LAST_MODIFIED_BY))) + continue properties; writeStart(writer, withPrefix(p.getName(), withPrefix)); writer.write(value.getString()); writeEnd(writer, withPrefix(p.getName(), withPrefix)); } - } else { - Value value = p.getValue(); - String pName = p.getName(); - if (!withMetadata && (pName.equals(Jcr.JCR_PRIMARY_TYPE) || pName.equals(Jcr.JCR_UUID) - || pName.equals(Jcr.JCR_CREATED) || pName.equals(Jcr.JCR_CREATED_BY) - || pName.equals(Jcr.JCR_LAST_MODIFIED) || pName.equals(Jcr.JCR_LAST_MODIFIED_BY))) - continue properties; - writeStart(writer, withPrefix(p.getName(), withPrefix)); - writer.write(value.getString()); - writeEnd(writer, withPrefix(p.getName(), withPrefix)); } } // children - NodeIterator nit = node.getNodes(); - while (nit.hasNext()) { - toXmlElements(writer, nit.nextNode(), withMetadata, withPrefix); + if (node.hasNodes()) { + if (depth == null || depth > 0) { + NodeIterator nit = node.getNodes(); + while (nit.hasNext()) { + toXmlElements(writer, nit.nextNode(), depth == null ? null : depth - 1, withMetadata, withPrefix, + propertiesAsElements); + } + } + writeEnd(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); } - - writeEnd(writer, withPrefix(node.getPrimaryNodeType().getName(), withPrefix)); } private static String withPrefix(String str, boolean withPrefix) { @@ -112,6 +155,23 @@ public class JcrXmlUtils { writer.append("\">"); } + private static void writeStart(Writer writer, String tagName, Map attrs, boolean hasChildren) + throws IOException { + writer.append('<'); + writer.append(tagName); + for (String attr : attrs.keySet()) { + writer.append(' '); + writer.append(attr); + writer.append("=\""); + writer.append(attrs.get(attr)); + writer.append('\"'); + } + if (hasChildren) + writer.append('>'); + else + writer.append("/>"); + } + private static void writeEnd(Writer writer, String tagName) throws IOException { writer.append("