Can write properties as attributes in toXmlElements.
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 31 Oct 2020 11:22:21 +0000 (12:22 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 31 Oct 2020 11:22:21 +0000 (12:22 +0100)
org.argeo.jcr/src/org/argeo/jcr/Jcr.java
org.argeo.jcr/src/org/argeo/jcr/xml/JcrXmlUtils.java

index 5ce8017ca4120c14accae02dc6669f1d87176771..fe73b53f428a44fbc7ec7271757e0c99e40e4ca5 100644 (file)
@@ -36,19 +36,26 @@ import javax.jcr.version.VersionManager;
  * exceptions. Loosely inspired by Java's <code>Files</code> 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";
        /**
         * <code>jcr:name</code>, 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";
-
        /**
         * <code>jcr:path</code>, 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";
-
        /**
         * <code>jcr:primaryType</code> with prefix instead of namespace (as in
         * {@link Property#JCR_PRIMARY_TYPE}.
index 6f1a9226068dfbec66c6cbdf022d0e9ae0045696..2adb6a97ebd73d84ef7653a83dbb7f6500d9a736 100644 (file)
@@ -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 {
         * <code>false</code>.
         */
        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 <code>null</code> 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
+        *                             <code>false</code>, 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<String, String> 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<String, String> 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("</");
                writer.append(tagName);