+import org.argeo.api.gcr.CrName;
+
+public abstract class AbstractContent extends AbstractMap<QName, Object> implements Content {
+
+ @Override
+ public Set<Entry<QName, Object>> entrySet() {
+// Set<Entry<String, Object>> result = new HashSet<>();
+// for (String key : keys()) {
+// Entry<String, Object> entry = new Entry<String, Object>() {
+//
+// @Override
+// public String getKey() {
+// return key;
+// }
+//
+// @Override
+// public Object getValue() {
+// return get(key, Object.class);
+// }
+//
+// @Override
+// public Object setValue(Object value) {
+// throw new UnsupportedOperationException();
+// }
+//
+// };
+// result.add(entry);
+// }
+ Set<Entry<QName, Object>> result = new AttrSet();
+ return result;
+ }
+
+ protected abstract Iterable<QName> keys();
+
+ protected abstract void removeAttr(QName key);
+
+ @Override
+ public String getPath() {
+ List<Content> ancestors = new ArrayList<>();
+ collectAncestors(ancestors, this);
+ StringBuilder path = new StringBuilder();
+ for (Content c : ancestors) {
+ QName name = c.getName();
+ // FIXME
+ if (!CrName.ROOT.get().equals(name))
+ path.append('/').append(name);
+ }
+ return path.toString();
+ }
+
+ private void collectAncestors(List<Content> ancestors, Content content) {
+ if (content == null)
+ return;
+ ancestors.add(0, content);
+ collectAncestors(ancestors, content.getParent());
+ }