1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | package Torello.HTML; import Torello.HTML.helper.AttrRegEx; import Torello.Java.StringParse; import java.util.Properties; import java.util.regex.Matcher; import java.util.stream.Stream; class RetrieveAllAttr { static Properties allAV( final TagNode tn, final boolean keepQuotes, final boolean preserveKeysCase ) { Properties ret = new Properties(); // NOTE: OPTIMIZED, "closing-versions" of the TagNode, and TagNode's whose 'str' field is // is only longer than the token, itself, by 3 or less characters cannot have // attributes. // CHARS: '<', TOKEN, SPACE, '>' // RET: In that case, just return an empty 'Properties' instance. if (tn.isClosing || (tn.str.length() <= (tn.tok.length() + 3))) return ret; // This RegEx Matcher 'matches' against Attribute/InnerTag Key-Value Pairs. // m.group(1): UN-USED! (Includes Key, Equals-Sign, and Value). Not w/leading white-space // m.group(2): returns the 'key' portion of the key-value pair, before an '=' (equals-sign) // m.group(3): returns the 'value' portion of the key-value pair, after an '=' Matcher m = AttrRegEx.KEY_VALUE_REGEX.matcher(tn.str); // MORE-CODE, but MORE-EFFICIENT (slightly) if (keepQuotes && preserveKeysCase) while (m.find()) ret.put(m.group(2), m.group(3)); else if (!keepQuotes && preserveKeysCase) while (m.find()) ret.put(m.group(2), StringParse.ifQuotesStripQuotes(m.group(3))); else if (keepQuotes && !preserveKeysCase) while (m.find()) ret.put(m.group(2).toLowerCase(), m.group(3)); else if (!keepQuotes && !preserveKeysCase) while (m.find()) ret.put(m.group(2).toLowerCase(), StringParse.ifQuotesStripQuotes(m.group(3))); return ret; } public static Stream<String> allAN( final TagNode tn, final boolean preserveKeysCase, final boolean includeKeyOnlyAttributes ) { // If there is NO ROOM in the "str" field for attributes, then there is now way attributes // could exist in this element. Return "empty" immediately. // // NOTE: OPTIMIZED, "closing-versions" of the TagNode, and TagNode's whose 'str' field // is only longer than the token, itself, by 3 or less characters cannot have // attributes. // // CHARS: '<', TOKEN, SPACE, '>' // RET: In that case, just return an empty Stream. if (tn.isClosing || (tn.str.length() <= (tn.tok.length() + 3))) return Stream.empty(); // Use Java Streams. A String-Stream is easily converted to just about any data-type Stream.Builder<String> b = Stream.builder(); // This RegEx Matcher 'matches' against Attribute/InnerTag Key-Value Pairs. // m.group(2): returns the 'key' portion of the key-value pair, before an '=' (equals-sign) Matcher m = AttrRegEx.KEY_VALUE_REGEX.matcher(tn.str); // Retrieve all of the keys of the attribute key-value pairs. while (m.find()) b.add(m.group(2)); // This Stream contains only keys that were once key-value pairs, if there are "key-only" // attributes, they have not been added yet. Stream<String> ret = b.build(); // Convert these to lower-case, (if requested) if (! preserveKeysCase) ret = ret.map((String attribute) -> attribute.toLowerCase()); // Now, add in all the "Key-Only" attributes (if there are any). Note, "preserve-case" // and "to lower case" are handled, already, in method "allKeyOnlyAttributes(boolean)" if (includeKeyOnlyAttributes) return Stream.concat (ret, KeyOnlyAttributes.allKeyOnlyAttributes(tn, preserveKeysCase)); return ret; } } |