People will have different approaches to dealing with XML manipulations. The variety of answers to this question is proof enough of this. While using regex and raw text manipulation might be good for one off fixes and hacks if you want a good and maintainable solution you should use an XML API.
My example below does what is asked, however it should be noted that I didn't check for any pathological inputs like (""
as the search string) or deal with XML namespaces. Those things can be added easily enough.
See comments in the code for description of how it works.
Input (test.xml):
<Callouts>
<Callout>Save the User Guide.</Callout>
</Callouts>
Program
package com.stackoverflow._18774666;
import java.net.URL;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class InsertElementInTextNode {
/**
* Replace text content of child text nodes of a parent element that
* matches a search string. The text is replace by an element named with the
* given name and has it's text content set equal to the search string.
*
* @param parent
* The element to search child text nodes of.
* @param elementName
* The name of the element to insert.
* @param text
* The text to replace with an element with same text content.
*/
public static void replaceTextWithElement(Element parent, String elementName, String text){
NodeList children = parent.getChildNodes();
Text cursor;
Element insertedElement;
int index;
/* Iterate children of the given element. */
for(int i = 0; i < children.getLength(); i++ ){
/* Check if this child is a text node. Ignore otherwise. */
if(children.item(i) instanceof Text){
cursor = (Text) children.item(i);
/* If the entire text node is equal to the search string,
* then we can replace it directly. Else we have split it.*/
if(text.equals(cursor.getData())){
/* Replace the text node with an element */
insertedElement = parent.getOwnerDocument().createElement(elementName);
insertedElement.setTextContent(text);
parent.replaceChild(insertedElement, cursor);
} else {
/* Check to see if the search string exists in this text node. Ignore otherwise.*/
index = cursor.getData().indexOf(text);
if(index != -1){
/* Replace the matched substring with an empty string.*/
cursor.replaceData(index, text.length(), "");
/* Create element to be inserted, and set the text content. */
insertedElement = parent.getOwnerDocument().createElement(elementName);
insertedElement.setTextContent(text);
/* Split the text node and insert the element in the middle. */
parent.insertBefore(insertedElement, cursor.splitText(index));
}
}
}
}
}
public static void main(String[] args) throws Exception {
/* Location of our XML document. */
URL xmlSource = InsertElementInTextNode.class.getResource("test.xml");
/* Parse with DOM in to a Document */
Document xmlDoc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(xmlSource.openStream());
/* Find our interesting elements. */
NodeList nodes = xmlDoc.getElementsByTagName("Callout");
/* Iterate through our interesting elements and check their content.*/
Element cursor;
for(int i = 0; i < nodes.getLength(); i++ ){
if(nodes.item(i) instanceof Element){
cursor = (Element) nodes.item(i);
replaceTextWithElement(cursor, "BookTitle", "User Guide");
}
}
/* Setup to output result. */
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
/* Printing result to stdout. */
transformer.transform(new DOMSource(xmlDoc),
new StreamResult(System.out));
}
}
Output (stdout):
<Callouts>
<Callout>Save the <BookTitle>User Guide</BookTitle>.</Callout>
</Callouts>