Created
March 22, 2017 10:33
-
-
Save tpb1908/570f2a8aae1e01f4931a5d77be16e839 to your computer and use it in GitHub Desktop.
Extract attributes from XmlReader in Android HtmlTagHandler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class HtmlTagHandler implements Html.TagHandler { | |
private static final String TAG = HtmlTagHandler.class.getSimpleName(); | |
@Override | |
public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) { | |
if(opening) { | |
if(tag.equalsIgnoreCase("a")) { | |
start(output, new A(getAttribute("href", xmlReader, "error.com"))); | |
} | |
} else { | |
if(tag.equalsIgnoreCase("a")) { | |
A obj = getLast(output, A.class); | |
// start of the tag | |
int where = output.getSpanStart(obj); | |
// end of the tag | |
int len = output.length(); | |
//TODO- | |
//Do something with your attribute | |
} | |
} | |
} | |
private void start(Editable output, Object mark) { | |
final int len = output.length(); | |
output.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK); | |
} | |
/** | |
* Modified from {@link android.text.Html} | |
*/ | |
private void end(Editable output, Class kind, boolean paragraphStyle, Object... replaces) { | |
Object obj = getLast(output, kind); | |
// start of the tag | |
int where = output.getSpanStart(obj); | |
// end of the tag | |
int len = output.length(); | |
output.removeSpan(obj); | |
if(where != len) { | |
int thisLen = len; | |
// paragraph styles like AlignmentSpan need to end with a new line! | |
if(paragraphStyle) { | |
output.append("\n"); | |
thisLen++; | |
} | |
for(Object replace : replaces) { | |
output.setSpan(replace, where, thisLen, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); | |
} | |
} | |
} | |
/** | |
* Returns the text contained within a span and deletes it from the output string | |
*/ | |
private CharSequence extractSpanText(Editable output, Class kind) { | |
final Object obj = getLast(output, kind); | |
// start of the tag | |
final int where = output.getSpanStart(obj); | |
// end of the tag | |
final int len = output.length(); | |
final CharSequence extractedSpanText = output.subSequence(where, len); | |
output.delete(where, len); | |
return extractedSpanText; | |
} | |
private static <T> T getLast(Editable text, Class<T> kind) { | |
final T[] objs = text.getSpans(0, text.length(), kind); | |
if(objs.length == 0) { | |
return null; | |
} else { | |
for(int i = objs.length; i > 0; i--) { | |
if(text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) { | |
return objs[i - 1]; | |
} | |
} | |
return null; | |
} | |
} | |
private static String getAttribute(@NonNull String attr, @NonNull XMLReader reader, String defaultAttr) { | |
try { | |
final Field elementField = reader.getClass().getDeclaredField("theNewElement"); | |
elementField.setAccessible(true); | |
final Object element = elementField.get(reader); | |
final Field attsField = element.getClass().getDeclaredField("theAtts"); | |
attsField.setAccessible(true); | |
final Object atts = attsField.get(element); | |
final Field dataField = atts.getClass().getDeclaredField("data"); | |
dataField.setAccessible(true); | |
final String[] data = (String[]) dataField.get(atts); | |
final Field lengthField = atts.getClass().getDeclaredField("length"); | |
lengthField.setAccessible(true); | |
final int len = (Integer) lengthField.get(atts); | |
for(int i = 0; i < len; i++) { | |
if(attr.equals(data[i * 5 + 1])) { | |
return data[i * 5 + 4]; | |
} | |
} | |
} catch(Exception e) { | |
Log.e(TAG, "handleTag: ", e); | |
} | |
return defaultAttr; | |
} | |
private static class A { | |
String href; | |
A(String href) { | |
this.href = href; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment