diff --git a/html-parser-api/src/main/java/ru/noties/markwon/html/HtmlTag.java b/html-parser-api/src/main/java/ru/noties/markwon/html/HtmlTag.java
index 153b4a77..06712012 100644
--- a/html-parser-api/src/main/java/ru/noties/markwon/html/HtmlTag.java
+++ b/html-parser-api/src/main/java/ru/noties/markwon/html/HtmlTag.java
@@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.List;
+import java.util.Map;
/**
* @see Inline
@@ -32,6 +33,9 @@ public interface HtmlTag {
*/
boolean isEmpty();
+ @NonNull
+ Map attributes();
+
/**
* Represents really inline HTML tags (unline commonmark definitions)
*/
diff --git a/html-parser-impl/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java b/html-parser-impl/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java
index 4f6ca844..83a77173 100644
--- a/html-parser-impl/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java
+++ b/html-parser-impl/src/main/java/ru/noties/markwon/html/HtmlTagImpl.java
@@ -5,6 +5,7 @@ import android.support.annotation.Nullable;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
abstract class HtmlTagImpl implements HtmlTag {
@@ -12,11 +13,13 @@ abstract class HtmlTagImpl implements HtmlTag {
final String name;
final int start;
+ final Map attributes;
int end = NO_VALUE;
- protected HtmlTagImpl(@NonNull String name, int start) {
+ protected HtmlTagImpl(@NonNull String name, int start, @NonNull Map attributes) {
this.name = name;
this.start = start;
+ this.attributes = attributes;
}
@NonNull
@@ -40,16 +43,23 @@ abstract class HtmlTagImpl implements HtmlTag {
return start == end;
}
+ @NonNull
+ @Override
+ public Map attributes() {
+ return attributes;
+ }
+
boolean isClosed() {
return end > NO_VALUE;
}
abstract void closeAt(int end);
+
static class InlineImpl extends HtmlTagImpl implements Inline {
- InlineImpl(@NonNull String name, int start) {
- super(name, start);
+ InlineImpl(@NonNull String name, int start, @NonNull Map attributes) {
+ super(name, start, attributes);
}
@Override
@@ -65,6 +75,7 @@ abstract class HtmlTagImpl implements HtmlTag {
"name='" + name + '\'' +
", start=" + start +
", end=" + end +
+ ", attributes=" + attributes +
'}';
}
}
@@ -74,20 +85,28 @@ abstract class HtmlTagImpl implements HtmlTag {
@NonNull
static BlockImpl root() {
//noinspection ConstantConditions
- return new BlockImpl("", 0, null);
+ return new BlockImpl("", 0, null, null);
}
@NonNull
- static BlockImpl create(@NonNull String name, int start, @NonNull BlockImpl parent) {
- return new BlockImpl(name, start, parent);
+ static BlockImpl create(
+ @NonNull String name,
+ int start,
+ @NonNull Map attributes,
+ @NonNull BlockImpl parent) {
+ return new BlockImpl(name, start, attributes, parent);
}
final BlockImpl parent;
List children;
@SuppressWarnings("NullableProblems")
- BlockImpl(@NonNull String name, int start, @NonNull BlockImpl parent) {
- super(name, start);
+ BlockImpl(
+ @NonNull String name,
+ int start,
+ @NonNull Map attributes,
+ @NonNull BlockImpl parent) {
+ super(name, start, attributes);
this.parent = parent;
}
@@ -127,12 +146,24 @@ abstract class HtmlTagImpl implements HtmlTag {
return (List) (List extends Block>) children;
}
+ @NonNull
+ @Override
+ public Map attributes() {
+ //noinspection ConstantConditions
+ if (attributes == null) {
+ throw new IllegalStateException("#attributes() getter was called on the root node " +
+ "which should not be exposed outside internal usage");
+ }
+ return attributes;
+ }
+
@Override
public String toString() {
return "BlockImpl{" +
"name='" + name + '\'' +
", start=" + start +
", end=" + end +
+ ", attributes=" + attributes +
", parent=" + (parent != null ? parent.name : null) +
", children=" + children +
'}';
diff --git a/html-parser-impl/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java b/html-parser-impl/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java
index b6b731a8..72aefad6 100644
--- a/html-parser-impl/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java
+++ b/html-parser-impl/src/main/java/ru/noties/markwon/html/MarkwonHtmlParserImpl.java
@@ -7,14 +7,19 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import ru.noties.markwon.html.HtmlTag.Block;
import ru.noties.markwon.html.HtmlTag.Inline;
import ru.noties.markwon.html.HtmlTagImpl.BlockImpl;
import ru.noties.markwon.html.HtmlTagImpl.InlineImpl;
+import ru.noties.markwon.html.jsoup.nodes.Attribute;
+import ru.noties.markwon.html.jsoup.nodes.Attributes;
import ru.noties.markwon.html.jsoup.parser.CharacterReader;
import ru.noties.markwon.html.jsoup.parser.ParseErrorList;
import ru.noties.markwon.html.jsoup.parser.Token;
@@ -209,7 +214,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
final String name = startTag.normalName;
- final InlineImpl inline = new InlineImpl(name, output.length());
+ final InlineImpl inline = new InlineImpl(name, output.length(), extractAttributes(startTag));
if (isVoidTag(name)
|| startTag.selfClosing) {
@@ -271,7 +276,7 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
final int start = output.length();
- final BlockImpl block = BlockImpl.create(name, start, currentBlock);
+ final BlockImpl block = BlockImpl.create(name, start, extractAttributes(startTag), currentBlock);
final boolean isVoid = isVoidTag(name) || startTag.selfClosing;
if (isVoid) {
@@ -396,4 +401,25 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
append(output, "\n");
}
}
+
+ @NonNull
+ protected static Map extractAttributes(@NonNull Token.StartTag startTag) {
+
+ Map map;
+
+ final Attributes attributes = startTag.attributes;
+ final int size = attributes.size();
+
+ if (size > 0) {
+ map = new HashMap<>(size);
+ for (Attribute attribute : attributes) {
+ map.put(attribute.getKey().toLowerCase(Locale.US), attribute.getValue());
+ }
+ map = Collections.unmodifiableMap(map);
+ } else {
+ map = Collections.emptyMap();
+ }
+
+ return map;
+ }
}
diff --git a/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java b/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java
index fea596e2..934dc364 100644
--- a/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java
+++ b/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attribute.java
@@ -137,13 +137,13 @@ public class Attribute implements Map.Entry, Cloneable {
// return new Attribute(unencodedKey, value, null); // parent will get set when Put
// }
- protected boolean isDataAttribute() {
- return isDataAttribute(key);
- }
-
- protected static boolean isDataAttribute(String key) {
- return key.startsWith(Attributes.dataPrefix) && key.length() > Attributes.dataPrefix.length();
- }
+// protected boolean isDataAttribute() {
+// return isDataAttribute(key);
+// }
+//
+// protected static boolean isDataAttribute(String key) {
+// return key.startsWith(Attributes.dataPrefix) && key.length() > Attributes.dataPrefix.length();
+// }
// /**
// * Collapsible if it's a boolean attribute and value is empty or same as name
diff --git a/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java b/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java
index f00ecfe1..d91033e5 100644
--- a/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java
+++ b/html-parser-impl/src/main/java/ru/noties/markwon/html/jsoup/nodes/Attributes.java
@@ -28,7 +28,7 @@ import static ru.noties.markwon.html.jsoup.helper.Normalizer.lowerCase;
* @author Jonathan Hedley, jonathan@hedley.net
*/
public class Attributes implements Iterable, Cloneable {
- protected static final String dataPrefix = "data-";
+// protected static final String dataPrefix = "data-";
private static final int InitialCapacity = 4; // todo - analyze Alexa 1MM sites, determine best setting
// manages the key/val arrays
@@ -282,14 +282,14 @@ public class Attributes implements Iterable, Cloneable {
return Collections.unmodifiableList(list);
}
- /**
- * Retrieves a filtered view of attributes that are HTML5 custom data attributes; that is, attributes with keys
- * starting with {@code data-}.
- * @return map of custom data attributes.
- */
- public Map dataset() {
- return new Dataset(this);
- }
+// /**
+// * Retrieves a filtered view of attributes that are HTML5 custom data attributes; that is, attributes with keys
+// * starting with {@code data-}.
+// * @return map of custom data attributes.
+// */
+// public Map dataset() {
+// return new Dataset(this);
+// }
// /**
// Get the HTML representation of these attributes.
@@ -380,65 +380,65 @@ public class Attributes implements Iterable, Cloneable {
}
}
- private static class Dataset extends AbstractMap {
- private final Attributes attributes;
+// private static class Dataset extends AbstractMap {
+// private final Attributes attributes;
+//
+// private Dataset(Attributes attributes) {
+// this.attributes = attributes;
+// }
+//
+// @Override
+// public Set> entrySet() {
+// return new EntrySet();
+// }
+//
+// @Override
+// public String put(String key, String value) {
+// String dataKey = dataKey(key);
+// String oldValue = attributes.hasKey(dataKey) ? attributes.get(dataKey) : null;
+// attributes.put(dataKey, value);
+// return oldValue;
+// }
+//
+// private class EntrySet extends AbstractSet> {
+//
+// @Override
+// public Iterator> iterator() {
+// return new DatasetIterator();
+// }
+//
+// @Override
+// public int size() {
+// int count = 0;
+// Iterator iter = new DatasetIterator();
+// while (iter.hasNext())
+// count++;
+// return count;
+// }
+// }
+//
+// private class DatasetIterator implements Iterator> {
+// private Iterator attrIter = attributes.iterator();
+// private Attribute attr;
+// public boolean hasNext() {
+// while (attrIter.hasNext()) {
+// attr = attrIter.next();
+// if (attr.isDataAttribute()) return true;
+// }
+// return false;
+// }
+//
+// public Entry next() {
+// return new Attribute(attr.getKey().substring(dataPrefix.length()), attr.getValue());
+// }
+//
+// public void remove() {
+// attributes.remove(attr.getKey());
+// }
+// }
+// }
- private Dataset(Attributes attributes) {
- this.attributes = attributes;
- }
-
- @Override
- public Set> entrySet() {
- return new EntrySet();
- }
-
- @Override
- public String put(String key, String value) {
- String dataKey = dataKey(key);
- String oldValue = attributes.hasKey(dataKey) ? attributes.get(dataKey) : null;
- attributes.put(dataKey, value);
- return oldValue;
- }
-
- private class EntrySet extends AbstractSet> {
-
- @Override
- public Iterator> iterator() {
- return new DatasetIterator();
- }
-
- @Override
- public int size() {
- int count = 0;
- Iterator iter = new DatasetIterator();
- while (iter.hasNext())
- count++;
- return count;
- }
- }
-
- private class DatasetIterator implements Iterator> {
- private Iterator attrIter = attributes.iterator();
- private Attribute attr;
- public boolean hasNext() {
- while (attrIter.hasNext()) {
- attr = attrIter.next();
- if (attr.isDataAttribute()) return true;
- }
- return false;
- }
-
- public Entry next() {
- return new Attribute(attr.getKey().substring(dataPrefix.length()), attr.getValue());
- }
-
- public void remove() {
- attributes.remove(attr.getKey());
- }
- }
- }
-
- private static String dataKey(String key) {
- return dataPrefix + key;
- }
+// private static String dataKey(String key) {
+// return dataPrefix + key;
+// }
}
\ No newline at end of file