+ /**
+ * Get the recursive state of the current object, i.e., its children
+ * included. It represents the full state information about this object's
+ * children. It may not contains spaces nor new lines.
+ *
+ * <p>
+ * Not that this state is <b>lossy</b>. You cannot retrieve the data from
+ * the state, it can only be used as an ID to check if data are identical.
+ * </p>
+ *
+ * @param self
+ * also include state information about the current object itself
+ * (as opposed to its children)
+ *
+ * @return a {@link String} representing the current content state of this
+ * object, i.e., its children included
+ */
+ public String getContentState(boolean self) {
+ StringBuilder builder = new StringBuilder();
+ buildContentStateRaw(builder, self);
+ return StringUtils.getHash(builder.toString());
+ }
+
+ /**
+ * Return the (first) child element with the given ID or NULL if not found.
+ *
+ * @param id
+ * the id to look for
+ *
+ * @return the child element or NULL
+ */
+ public E getById(String id) {
+ for (E child : this) {
+ if (id == null) {
+ if (child.getId() == null)
+ return child;
+ } else {
+ if (id.equals(child.getId()))
+ return child;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a {@link String} that can be used to identify this object in DEBUG
+ * mode, i.e., a "toString" method that can identify the object's content
+ * but still be readable in a log.
+ *
+ * @param depth
+ * the depth into which to descend (0 = only this object, not its
+ * children)
+ *
+ * @return the debug {@link String}
+ */
+ public String getDebugInfo(int depth) {
+ StringBuilder builder = new StringBuilder();
+ getDebugInfo(builder, depth, 0);
+ return builder.toString();
+ }
+