List<Fragment> (@NotNull @Nls String htmlString, SimpleTextAttributes defaultAttributes) { TextAttributesStack attributesStack = new TextAttributesStack(defaultAttributes); List<Fragment> res = new ArrayList<>(); HTMLEditorKit.ParserCallback callback = new HTMLEditorKit.ParserCallback() { @Override public void handleText(char[] data, int pos) { res.add(new Fragment(new String(data), attributesStack.peek())); } @Override public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { String tagName = t.toString(); SimpleTextAttributes attributesByTag = myStyleTagHandler.calcAttributes(t, a); if (attributesByTag != null) { SimpleTextAttributes newAttributes = merge( attributesStack.peek(), attributesByTag); attributesStack.push(tagName, newAttributes); } } @Override public void handleEndTag(HTML.Tag t, int pos) { attributesStack.removeFromTop(t.toString()); } @Override public void handleError(String errorMsg, int pos) { //since <body> tag may be skipped for this parser if (errorMsg.startsWith("start.missing body")) return; // style attribute can be processed by StyleTagHandler if (errorMsg.startsWith("invalid.tagatt style")) return; LOG.error("Cannot parse HTML: [" + htmlString + "]", errorMsg); } }; Reader reader = new StringReader(htmlString); try { new ParserDelegator().parse(reader, callback, true); } catch (IOException e) { LOG.error("Cannot parse HTML", e); return Collections.singletonList(new Fragment(StringUtil.removeHtmlTags(htmlString), defaultAttributes)); } return res; }