Converts this Node tree into a nested Map . Attributes and child elements are merged into a single map keyed by name. If a child element name collides with an attribute name, the child element wins. Leaf child elements (text only, no attributes) become String values. Non-l
()
| 906 | * @since 6.0.0 |
| 907 | */ |
| 908 | @SuppressWarnings("unchecked") |
| 909 | public Map<String, Object> toMap() { |
| 910 | Map<String, Object> map = new LinkedHashMap<>(); |
| 911 | |
| 912 | // copy attributes, tracking which keys came from attributes |
| 913 | java.util.Set<String> attributeKeys = new java.util.HashSet<>(); |
| 914 | for (Map.Entry<?, ?> entry : ((Map<?, ?>) attributes()).entrySet()) { |
| 915 | String key = nameAsString(entry.getKey()); |
| 916 | map.put(key, entry.getValue()); |
| 917 | attributeKeys.add(key); |
| 918 | } |
| 919 | |
| 920 | // process child nodes |
| 921 | boolean hasChildElements = false; |
| 922 | for (Object child : children()) { |
| 923 | if (child instanceof Node childNode) { |
| 924 | hasChildElements = true; |
| 925 | String key = nameAsString(childNode.name()); |
| 926 | Object childValue; |
| 927 | if (childNode.isLeaf() && childNode.attributes().isEmpty()) { |
| 928 | childValue = childNode.text(); |
| 929 | } else { |
| 930 | childValue = childNode.toMap(); |
| 931 | } |
| 932 | Object existing = map.get(key); |
| 933 | if (existing == null || attributeKeys.remove(key)) { |
| 934 | // first child element with this name (or replacing an attribute) |
| 935 | map.put(key, childValue); |
| 936 | } else if (existing instanceof List) { |
| 937 | ((List<Object>) existing).add(childValue); |
| 938 | } else { |
| 939 | List<Object> list = new ArrayList<>(); |
| 940 | list.add(existing); |
| 941 | list.add(childValue); |
| 942 | map.put(key, list); |
| 943 | } |
| 944 | } |
| 945 | } |
| 946 | |
| 947 | // if this node has attributes AND direct text, add _text entry |
| 948 | if (!attributes().isEmpty() && !hasChildElements) { |
| 949 | String text = text(); |
| 950 | if (!text.isEmpty()) { |
| 951 | map.put(TEXT_KEY, text); |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | return map; |
| 956 | } |
| 957 | |
| 958 | private static String nameAsString(Object name) { |
| 959 | if (name instanceof QName qn) { |
no test coverage detected