@Override public void characters(char[] ch, int start, int length) throws SAXException { LOGGER.trace("characters()"); if (top() == Action.KEEP) { if (activeText == null) { activeText = new Text(); currentParent.addChild(activeText); } activeText.appendContent(ch, start, length); } }
private void resetActiveText() { if (activeText != null) { activeText.setContent(textContentConverter.convertTextContent(activeText.getParent(), activeText.getContent())); activeText = null; } }
/** * Changes all texts locally. * * @param modifier A function that take content and returns new content. */ public default void changeTexts(Function<String, String> modifier) { for (final Text child : getTexts()) { final String content = child.getContent(); final String newContent = modifier.apply(content); if (Operators.notEquals(content, newContent)) { child.setContent(newContent); } } }
@Test public void testConstructors1() { final Text x = new Text(); assertEquals(NodeType.TEXT, x.getType()); assertEquals(null, x.getParent()); assertEquals("", x.getContent()); x.setContent(HELLO); assertEquals(HELLO, x.getContent()); x.clearContent(); assertEquals("", x.getContent()); x.appendContent(HELLO); assertEquals(HELLO, x.getContent()); x.appendContent(null); assertEquals(HELLO, x.getContent()); assertEquals(null, x.getRootElement()); assertEquals(null, x.getDocument()); assertEquals(x, x.getRootChild()); assertTrue(x.deepEquals(x)); assertFalse(x.deepEquals(null)); }
@Test public void testIsIgnorableWhiteSpace() { final Text x = new Text(); assertTrue(x.isIgnorable()); x.setContent(" "); assertTrue(x.isIgnorable()); x.setContent("\t"); assertTrue(x.isIgnorable()); x.setContent("\n"); assertTrue(x.isIgnorable()); x.setContent("\r"); assertTrue(x.isIgnorable()); x.setContent("\f"); assertTrue(x.isIgnorable()); x.setContent("a"); assertFalse(x.isIgnorable()); }
public Text(Text other) { super(null, other.getContent()); }
@Test public void testClone() { final Text x1 = new Text(null, HELLO); final Text x2 = x1.clone(false); final Text x3 = x1.clone(true); assertNotEquals(x1, x2); assertNotEquals(x1, x3); assertTrue(x1.deepEquals(x2)); assertTrue(x2.deepEquals(x1)); }
/** * Removes active text if possible and necessary. * * @param preserve If {@code true} should be preserved if necessary. * * @throws SAXException When mixed content is found and is not allowed. */ private void checkActiveText(boolean preserve) throws SAXException { if (activeText != null) { if (preserve && currentParent.getChildrenCount() == 1) { // Preserve the text that is the only child of its parent (element) resetActiveText(); } else if (activeText.getContent().isEmpty() || activeText.isIgnorable() && !isEnabled(Feature.LOAD_SPACES)) { currentParent.removeChildAt(currentParent.getChildrenCount() - 1); resetActiveText(); } else if (currentParent.getChildrenCount() > 1 && !isEnabled(Feature.ALLOW_MIXED_CONTENT)) { throw new SAXException("Mixed content not allowed"); } } }
if (child.getChildrenCount(Text.class) == 1 && newContent != null && !newContent.isEmpty()) { final Text text = child.getChild(Text.class); text.clearContent(); text.appendContent(newContent); } else { child.removeChildren();
/** * Merges all consecutive texts locally. */ public default void mergeTexts() { if (getChildrenCount() > 1) { Child ref = getChildAt(0); int index = 1; while (index < getChildrenCount()) { final Child next = getChildAt(index); if (ref.getType() == NodeType.TEXT && next.getType() == NodeType.TEXT) { // ref and next are both texts: merge them ((Text) ref).appendContent(((Text) next).getContent()); // Remove next next.detach(); // Do not change index and ref } else { ref = next; index++; } } } }
@Test public void testGetRootElement() { final Text x = new Text(HELLO); assertEquals(null, x.getRootElement()); final Element root = new Element(NAME); root.addChild(x); assertEquals(root, x.getRootElement()); } }
@Test public void testChildren() { final Element e = new Element(NAME); assertEquals(null, e.getDocument()); assertEquals(e, e.getRootElement()); assertEquals(e, e.getRootChild()); final Element c0 = e.addElement(NAME1); final Element c1 = e.addElement(NAME1); final Text c2 = e.addText("Hello"); final Comment c3 = e.addComment("Hello"); assertEquals(c0, e.getChildAt(0)); assertEquals(c1, e.getChildAt(1)); assertEquals(c0, e.getElementNamed(NAME1)); assertEquals(null, c2.getDocument()); assertEquals(e, c3.getRootElement()); assertEquals(e, c3.getRootChild()); assertEquals(e, c2.getParent()); assertEquals(e, c2.getParent(Element.class)); assertEquals(4, e.getChildrenCount()); assertEquals(4, e.getChildrenCount(Node.class)); assertEquals(2, e.getChildrenCount(Element.class)); assertEquals(1, e.getChildrenCount(Comment.class)); assertEquals(1, e.getChildrenCount(Text.class)); assertEquals(2, e.getChildrenCount(Parent.class)); assertEquals(4, e.getChildrenCount(Child.class)); assertEquals(2, e.getChildrenCount(Leaf.class)); }
@Override public Text clone(boolean recurse) { return new Text(this); }
@Override public String getQName() { return getParent().getQName() + "/text()"; }
@Test public void testConstructors2() { final Document doc = new Document(); final Text x = new Text(doc); assertEquals(NodeType.TEXT, x.getType()); assertEquals(doc, x.getParent()); assertEquals("", x.getContent()); x.setContent(HELLO); assertEquals(HELLO, x.getContent()); x.clearContent(); assertEquals("", x.getContent()); x.appendContent(HELLO); assertEquals(HELLO, x.getContent()); x.appendContent(null); assertEquals(HELLO, x.getContent()); assertEquals(null, x.getRootElement()); assertEquals(doc, x.getDocument()); assertEquals(x, x.getRootChild()); }
/** * Sets the content of matching texts. * <p> * Uses a Depth First traversal for recursion. * * @param parent The initial node. <em>MUST NOT</em> be null. * @param predicate The predicate of matching texts. <em>MUST NOT</em> be null. * @param converter The content converter. * @param evaluator The evaluator. <em>MUST NOT</em> be null. */ public static void setContentOfMatchingTexts(Parent parent, TextPredicate predicate, TextContentConverter converter, Evaluator<? super Parent> evaluator) { for (final Child child : parent.getChildren()) { if (child instanceof Text) { final Text text = (Text) child; if (predicate.accepts(parent, text)) { final String content = converter.convertTextContent(parent, text.getContent()); text.setContent(content); } } else if (child instanceof Parent && evaluator.evaluate((Parent) child) == Evaluation.CONTINUE) { setContentOfMatchingTexts((Parent) child, predicate, converter, evaluator); } } }
public boolean isIgnorable() { return XmlUtil.isIgnorableSpace(getContent()); } }
public static void setContentOfMatchingElements(Parent parent, ElementPredicate predicate, TextContentConverter converter, Evaluator<? super Parent> evaluator) { if (parent instanceof Element) { final Element element = (Element) parent; if (predicate.accepts(element.getParent(), element)) { final int count = element.getChildrenCount(); if (count == 0) { // Add a text child final String content = converter.convertTextContent(element, null); if (content != null) { element.addText(content); } } else if (count == 1 && element.hasOnlyText()) { // Modify text child if possible final Text text = element.getChild(Text.class); final String content = converter.convertTextContent(element, text.getContent()); text.setContent(content); } } } for (final Child child : parent.getChildren()) { if (child instanceof Parent && evaluator.evaluate((Parent) child) == Evaluation.CONTINUE) { setContentOfMatchingElements((Parent) child, predicate, converter, evaluator); } } }
/** * Adds a text as last child. * * @param content The text content. * @param merge If {@code true}, then if last child exists and is a text, * {@code content} is added to this last child.<br> * Otherwise, a text child is created and added to last position. * @return The modified or created text. */ public Text addText(String content, boolean merge) { if (merge) { final Child last = getLastChild(); if (last != null && last.getType() == NodeType.TEXT) { ((Text) last).appendContent(content); return (Text) last; } } final Text result = new Text(content); addChild(result); return result; }
/** * Returns the merged content of all children text nodes, if this node has no element children. * <p> * This will work when this node has only text and comment children.<br> * If it has element children, the default value is returned. * * @param def The default value. * @return The merged content of children texts (ignoring comments) or {@code def}. */ public String getText(String def) { if (children == null || children.isEmpty()) { return def; } else if (!hasChildren(Element.class)) { // Ignore comments final Iterable<Text> texts = getChildren(Text.class); if (Iterables.isEmpty(texts)) { return def; } else { final StringBuilder sb = new StringBuilder(); for (final Text text : texts) { sb.append(text.getContent()); } return sb.toString(); } } else { return def; } }