171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistpackage com.android.server.wifi.hotspot2.omadm; 271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport org.xml.sax.Attributes; 471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport org.xml.sax.SAXException; 571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.io.IOException; 771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.ArrayList; 871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.Arrays; 971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.Collections; 1071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.HashMap; 111d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvistimport java.util.HashSet; 12c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvistimport java.util.Iterator; 1371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.List; 1471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistimport java.util.Map; 151d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvistimport java.util.Set; 1671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 1771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvistpublic class XMLNode { 1871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private final String mTag; 1971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private final Map<String, NodeAttribute> mAttributes; 2071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private final List<XMLNode> mChildren; 2171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private final XMLNode mParent; 2271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private MOTree mMO; 2371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private StringBuilder mTextBuilder; 2471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private String mText; 2571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 261d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static final String XML_SPECIAL_CHARS = "\"'<>&"; 271d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static final Set<Character> XML_SPECIAL = new HashSet<>(); 281d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static final String CDATA_OPEN = "<![CDATA["; 291d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static final String CDATA_CLOSE = "]]>"; 301d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 311d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist static { 321d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (int n = 0; n < XML_SPECIAL_CHARS.length(); n++) { 331d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist XML_SPECIAL.add(XML_SPECIAL_CHARS.charAt(n)); 341d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 351d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 361d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 3771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public XMLNode(XMLNode parent, String tag, Attributes attributes) throws SAXException { 3871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTag = tag; 3971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 401d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mAttributes = new HashMap<>(); 4171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 4271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist if (attributes.getLength() > 0) { 4371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist for (int n = 0; n < attributes.getLength(); n++) 4471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mAttributes.put(attributes.getQName(n), new NodeAttribute(attributes.getQName(n), 4571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist attributes.getType(n), attributes.getValue(n))); 4671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 4771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 4871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mParent = parent; 491d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mChildren = new ArrayList<>(); 5071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 5171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTextBuilder = new StringBuilder(); 5271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 5371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 541d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist public XMLNode(XMLNode parent, String tag, Map<String, String> attributes) { 551d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mTag = tag; 561d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 571d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mAttributes = new HashMap<>(attributes == null ? 0 : attributes.size()); 581d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 591d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (attributes != null) { 601d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (Map.Entry<String, String> entry : attributes.entrySet()) { 611d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mAttributes.put(entry.getKey(), new NodeAttribute(entry.getKey(), "", entry.getValue())); 621d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 631d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 641d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 651d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mParent = parent; 661d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mChildren = new ArrayList<>(); 671d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 681d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mTextBuilder = new StringBuilder(); 691d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 701d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 71c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist @Override 72c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist public boolean equals(Object thatObject) { 73c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist if (thatObject == this) { 74c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return true; 75c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } else if (thatObject.getClass() != XMLNode.class) { 76c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return false; 77c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 78c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist 79c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist XMLNode that = (XMLNode) thatObject; 80c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist if (!getTag().equals(that.getTag()) 81c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist || mAttributes.size() != that.mAttributes.size() 82c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist || mChildren.size() != that.mChildren.size()) { 83c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return false; 84c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 85c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist 86c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { 87c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist if (!entry.getValue().equals(that.mAttributes.get(entry.getKey()))) { 88c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return false; 89c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 90c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 91c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist 92c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist List<XMLNode> cloneOfThat = new ArrayList<>(that.mChildren); 93c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist for (XMLNode child : mChildren) { 94c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist Iterator<XMLNode> thatChildren = cloneOfThat.iterator(); 95c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist boolean found = false; 96c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist while (thatChildren.hasNext()) { 97c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist XMLNode thatChild = thatChildren.next(); 98c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist if (child.equals(thatChild)) { 99c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist found = true; 100c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist thatChildren.remove(); 101c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist break; 102c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 103c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 104c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist if (!found) { 105c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return false; 106c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 107c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 108c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return true; 109c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 110c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist 1111d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist public void setText(String text) { 1121d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mText = text; 1131d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mTextBuilder = null; 1141d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1151d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 11671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public void addText(char[] chs, int start, int length) { 11771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist String s = new String(chs, start, length); 11871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist String trimmed = s.trim(); 11971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist if (trimmed.isEmpty()) 12071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return; 12171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 12271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist if (s.charAt(0) != trimmed.charAt(0)) 12371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTextBuilder.append(' '); 12471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTextBuilder.append(trimmed); 12571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist if (s.charAt(s.length() - 1) != trimmed.charAt(trimmed.length() - 1)) 12671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTextBuilder.append(' '); 12771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 12871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 12971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public void addChild(XMLNode child) { 13071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mChildren.add(child); 13171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 13271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 13371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public void close() throws IOException, SAXException { 13471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist String text = mTextBuilder.toString().trim(); 13571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist StringBuilder filtered = new StringBuilder(text.length()); 13671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist for (int n = 0; n < text.length(); n++) { 13771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist char ch = text.charAt(n); 13871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist if (ch >= ' ') 13971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist filtered.append(ch); 14071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 14171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 14271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mText = filtered.toString(); 14371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist mTextBuilder = null; 14471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 1451d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (MOTree.hasMgmtTreeTag(mText)) { 1461d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist try { 1471d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist NodeAttribute urn = mAttributes.get(OMAConstants.SppMOAttribute); 1481d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist OMAParser omaParser = new OMAParser(); 1491d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mMO = omaParser.parse(mText, urn != null ? urn.getValue() : null); 1501d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1511d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist catch (SAXException | IOException e) { 1521d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist mMO = null; 1531d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 15471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 15571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 15671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 15771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public String getTag() { 15871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return mTag; 15971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 16071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 1611d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist public String getNameSpace() throws OMAException { 1621d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist String[] nsn = mTag.split(":"); 1631d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (nsn.length != 2) { 1641d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist throw new OMAException("Non-namespaced tag: '" + mTag + "'"); 1651d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1661d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return nsn[0]; 1671d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1681d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 1691d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist public String getStrippedTag() throws OMAException { 1701d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist String[] nsn = mTag.split(":"); 1711d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (nsn.length != 2) { 1721d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist throw new OMAException("Non-namespaced tag: '" + mTag + "'"); 1731d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1741d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return nsn[1].toLowerCase(); 1751d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1761d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 1771d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist public XMLNode getSoleChild() throws OMAException{ 1781d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (mChildren.size() != 1) { 1791d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist throw new OMAException("Expected exactly one child to " + mTag); 1801d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1811d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return mChildren.get(0); 1821d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 1831d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 18471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public XMLNode getParent() { 18571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return mParent; 18671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 18771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 18871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public String getText() { 18971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return mText; 19071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 19171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 19271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public Map<String, NodeAttribute> getAttributes() { 19371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return Collections.unmodifiableMap(mAttributes); 19471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 19571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 196c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist /** 197c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist * Get the attributes of this node as a map of attribute name to attribute value. 198c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist * @return The attribute mapping. 199c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist */ 200c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist public Map<String, String> getTextualAttributes() { 201c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist Map<String, String> map = new HashMap<>(mAttributes.size()); 202c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { 203c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist map.put(entry.getKey(), entry.getValue().getValue()); 204c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 205c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist return map; 206c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist } 207c9b88562541a0c2acd60d0a01ac1e182e73c79f9Jan Nordqvist 20871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public String getAttributeValue(String name) { 20971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist NodeAttribute nodeAttribute = mAttributes.get(name); 21071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return nodeAttribute != null ? nodeAttribute.getValue() : null; 21171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 21271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 21371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public List<XMLNode> getChildren() { 21471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return mChildren; 21571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 21671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 21771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public MOTree getMOTree() { 21871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return mMO; 21971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 22071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 22171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist private void toString(char[] indent, StringBuilder sb) { 22271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist Arrays.fill(indent, ' '); 22371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 2241d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(indent).append('<').append(mTag); 2251d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { 2261d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(' ').append(entry.getKey()).append("='").append(entry.getValue().getValue()).append('\''); 2271d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 22871a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 2291d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (mText != null && !mText.isEmpty()) { 2301d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append('>').append(escapeCdata(mText)).append("</").append(mTag).append(">\n"); 2311d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2321d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist else if (mChildren.isEmpty()) { 2331d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append("/>\n"); 2341d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2351d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist else { 2361d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(">\n"); 2371d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist char[] subIndent = Arrays.copyOf(indent, indent.length + 2); 2381d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (XMLNode child : mChildren) { 2391d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist child.toString(subIndent, sb); 2401d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2411d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(indent).append("</").append(mTag).append(">\n"); 2421d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2431d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 24471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 2451d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static String escapeCdata(String text) { 2461d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (!escapable(text)) { 2471d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return text; 2481d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 24971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 2501d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist // Any appearance of ]]> in the text must be split into "]]" | "]]>" | <![CDATA[ | ">" 2511d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist // i.e. "split the sequence by putting a close CDATA and a new open CDATA before the '>' 2521d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist StringBuilder sb = new StringBuilder(); 2531d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(CDATA_OPEN); 2541d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist int start = 0; 2551d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (;;) { 2561d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist int etoken = text.indexOf(CDATA_CLOSE); 2571d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (etoken >= 0) { 2581d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(text.substring(start, etoken + 2)).append(CDATA_CLOSE).append(CDATA_OPEN); 2591d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist start = etoken + 2; 2601d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2611d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist else { 2621d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (start < text.length() - 1) { 2631d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(text.substring(start)); 2641d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2651d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist break; 2661d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2671d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2681d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist sb.append(CDATA_CLOSE); 2691d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return sb.toString(); 2701d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2711d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist 2721d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist private static boolean escapable(String s) { 2731d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist for (int n = 0; n < s.length(); n++) { 2741d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist if (XML_SPECIAL.contains(s.charAt(n))) { 2751d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return true; 2761d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2771d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist } 2781d5cd3938f9191184cd9aea3059a3b62bf3a0372Jan Nordqvist return false; 27971a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 28071a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist 28171a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist @Override 28271a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist public String toString() { 28371a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist StringBuilder sb = new StringBuilder(); 28471a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist toString(new char[0], sb); 28571a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist return sb.toString(); 28671a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist } 28771a988c8e9859244b83cd55bb6b6ee913fcaf95cJan Nordqvist} 288