+
+ default boolean hasChild(QName name) {
+ for (Content child : this) {
+ if (child.getName().equals(name))
+ return true;
+ }
+ return false;
+ }
+
+ default boolean hasChild(QNamed name) {
+ return hasChild(name.qName());
+ }
+
+ default Content anyOrAddChild(QName name, QName... classes) {
+ Content child = anyChild(name);
+ if (child != null)
+ return child;
+ return this.add(name, classes);
+ }
+
+ default Content anyOrAddChild(String name, QName... classes) {
+ return anyOrAddChild(unqualified(name), classes);
+ }
+
+ /** Any child with this name, or null if there is none */
+ default Content anyChild(QName name) {
+ for (Content child : this) {
+ if (child.getName().equals(name))
+ return child;
+ }
+ return null;
+ }
+
+ default List<Content> children(QName name) {
+ List<Content> res = new ArrayList<>();
+ for (Content child : this) {
+ if (child.getName().equals(name))
+ res.add(child);
+ }
+ return res;
+ }
+
+ default Optional<Content> soleChild(QName name) {
+ List<Content> res = children(name);
+ if (res.isEmpty())
+ return Optional.empty();
+ if (res.size() > 1)
+ throw new IllegalStateException(this + " has multiple children with name " + name);
+ return Optional.of(res.get(0));
+ }
+
+ default Content child(QName name) {
+ return soleChild(name).orElseThrow();
+ }
+
+ default Content child(QNamed name) {
+ return child(name.qName());
+ }
+
+ /*
+ * ATTR AS STRING
+ */
+ default String attr(QName key) {
+ // TODO check String type?
+ Object obj = get(key);
+ if (obj == null)
+ return null;
+ return obj.toString();
+ }
+
+ default String attr(QNamed key) {
+ return attr(key.qName());
+ }
+
+ default String attr(String key) {
+ return attr(unqualified(key));
+ }