Hi,
How to edit the following xml file without losing elements.
eg:

<book id="b1">
  
      <bookbegin id="bb1">
  
      <para id="p1">This is<b>first</b>line</para>
  
      <para id="p2">This is<b>second</b>line</para>
  
      <para id="p3">This is<b>third</b>line</para>
   
      </bookbegin>
  
      </book>

I try to edit the above xml file using dtd using jsp,servlet. but while i read the textvalue from xml, it return only first,second,third.How to read the 'This is' and 'line '. Then how to store back to the xml file using xpath.

thank in advance.

Edited 6 Years Ago by peter_budo: Keep it Organized - For easy readability, always wrap programming code within posts in [code] (code blocks)

package xml.BO;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XpathGenerator {

    /*
     * fileList - a list of files to generate XPath expressions from xpath - an
     * xpath instance used to verify generated xpaths
    */
    private static List fileList = new ArrayList();
    private static XPath xpath = XPathFactory.newInstance().newXPath();
    ArrayList list=new ArrayList();
    /*
     * Simple utility method that checks for whitespace at the beginning a text
     * node
     */
    private boolean isWhiteSpace(String nodeText) {
        if (nodeText.startsWith("\r") || nodeText.startsWith("\t")
                || nodeText.startsWith("\n") || nodeText.startsWith(" "))
            return true;
        else
            return false;
    }

    /*
     * Simple utility method to verify brutishly assembled xpath expressions
     */
    private ArrayList checkXPath(String xpathExpression, Node node, String xpathExpression1) {
        Object xpathCheck;
        try {
            xpathCheck = xpath.evaluate(xpathExpression, node
                    .getOwnerDocument(), XPathConstants.BOOLEAN);
            if (xpathCheck.toString() == "true") {
                /*
                 * print the file/xpath combo to use for future verification For
                 * Example:
                 * file:/C:/tmp/sample.xml=/rootNode/firstChild/firstGrandChild
                 * [@attrib="value"][text()="some text"]
                 */
                //System.out.println(node+"\t"+xpathExpression+"\t"+node.getTextContent());
                list.add(node.getNodeName());
                list.add(xpathExpression1);
                list.add(node.getTextContent());
            }
        } catch (XPathExpressionException xpe) {
            System.out.println("\n\n" + xpathExpression);
            xpe.printStackTrace();
        }
        return list;
    }


    /*
     * Simple utility method to check for a text node on the currenrt XML
     * element
     */
    private boolean hasValidText(Node node) {
        String textValue = node.getTextContent();

        return (textValue != null && textValue != ""
                && isWhiteSpace(textValue) == false
                && !StringUtils.isWhitespace(textValue) && node.hasChildNodes());
    }

    /*
     * Simple utility to check for attributes on the current element
     */
    private boolean hasValidAttributes(Node node) {
        return (node.getAttributes().getLength() > 0);

    }

    /*
     * Build XPath attribute list for individual XML Element Nodes Iterate
     * through all attribute nodes and build a string that can be included in an
     * XPath expression to validate an XML document. Resulting string will look
     * like: [@attrib1="value1" and @attrib2="value2"] Skip this if the
     * attribute list is empty.
     */

    private String buildAttribString(Node node, String pathExpr) {
        NamedNodeMap nnlist = node.getAttributes();
        for (int i = 0; i < nnlist.getLength(); i++) {
            // grab attribute name and value
        String attribName = nnlist.item(i).getNodeName();
        String attribValue = nnlist.item(i).getNodeValue();

        if(!(attribName.contains(":")))
        {
        pathExpr = pathExpr + "[";

        int attribCount = 0;
        // iterate over attributes


            // if we've already added attributes to the path expression append
            // the current one

            if (attribCount > 0) {
                pathExpr = pathExpr + " and ";
            }

            pathExpr = pathExpr + "@" + attribName + "=\'" + attribValue + "\'";

            attribCount++;



        pathExpr = pathExpr + "]";
        }
      }
        return pathExpr;
    }

    /*
     * processNode checks for attributes and text nodes on an xml node and
     * process them accordingly
     */
public ArrayList processNode(Node node) {
        String pathExpr1=null;
        if (hasValidAttributes(node) || hasValidText(node)) {
            String pathExpr = "/" + node.getNodeName();

            // check for attributes
            if (hasValidAttributes(node)) {
                pathExpr = buildAttribString(node, pathExpr);
            }

            // Make a copy of node to preserve it's state
            Node tmpNode = node;

            // Build pathExpr for XPath Expression by working backward through
            // the XML until we hit the document node.
            while (tmpNode.getParentNode() != null
                    && tmpNode.getParentNode().getNodeType() != Node.DOCUMENT_NODE) {

                tmpNode = tmpNode.getParentNode();
                String nodeName = tmpNode.getNodeName();

                if (hasValidAttributes(tmpNode)) {
                    String attribString = buildAttribString(tmpNode, nodeName);
                    pathExpr = "/" + attribString + pathExpr;
                } else {
                    pathExpr = "/" + nodeName + pathExpr;
                }
            }

            if (hasValidText(node)) {

                /*
                 * Build XPath text value expression to verify text values for
                 * node. This is a little tricky because linebreaks, tabs and
                 * spaces included in the XML document are considered text
                 * nodes.
                 */

                // Copy original node to a textNode to preserve state of
                // original node for future operations
                Node textNode = node;

                /*
                 * This check iterates through child nodes of the original node
                 * until it reaches the next element node. As long as the node
                 * is not null, starts with white space and is not an element
                 * node, move on to the next node
                 */
                while (textNode != null
                          && isWhiteSpace(textNode.getTextContent()) == true
                          && StringUtils.isWhitespace(textNode.getTextContent())
                          && textNode.getNodeType() != Node.ELEMENT_NODE) {
                    textNode = textNode.getFirstChild();

                }

                /*
                 * If the text content of the current node is not null, doesn't
                 * start with whitespace and has child nodes, we grab the text
                 * and frame it into an XPath text argument. A sample element
                 * and it's resulting text argument:
                 * 
                 * some text here YIELDS
                 * element1[text()="some text here"]
                 * 
                 * NOTE: The check for child nodes prevents us from creating a
                 * blank text argument for self contained elements (example:
                 * )
                 */
                pathExpr1 =pathExpr;
                pathExpr = pathExpr + "[text()=\""
                               + StringUtils.strip(textNode.getTextContent()) + "\"]";
                //System.out.println(node);
                //System.out.println(textNode.getTextContent());
                //System.out.println(pathExpr);

            }

            list=checkXPath(pathExpr, node, pathExpr1);
        }
        // gather children and return
        return list;
    }

    // This function takes a group of nodes and generates XPath expressions for
    // them until it runs out of nodes
    public ArrayList processNodeList(NodeList nodelist) {

        for (int i = 0; i < nodelist.getLength(); i++) {
            if (nodelist.item(i).getNodeType() == Node.ELEMENT_NODE
                  && (hasValidAttributes(nodelist.item(i)) || hasValidText(nodelist
                        .item(i)))) {

                list= processNode(nodelist.item(i));
            }

            processNodeList(nodelist.item(i).getChildNodes());
        }
        return  list;
    }

    // This starts the process of an individual XML file
    private ArrayList processXML(File xmlFile) throws SAXException,
            IOException, ParserConfigurationException, XPathExpressionException {

        try {

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            factory.setIgnoringComments(true);
            //factory.setValidating(true);
            //factory.setNamespaceAware(true);
            factory.setIgnoringElementContentWhitespace(true);
            DocumentBuilder parser = factory.newDocumentBuilder();

            Document doc = parser.parse(xmlFile);

            NodeList startlist = doc.getChildNodes();

            list=processNodeList(startlist);

        } catch (Exception e) {
                System.out.println(e);
        }
        return list;
    }

    /*
     * Entry point. Pass in the xml file or top level directory of a group of
     * files to generate XPath expressions for them.
     */

    public ArrayList main1() {

        try {
            File startDir = new File("c:/xmleditor/dtd/0073404411_001_ch08.xml");
            if (startDir.isFile()) {

                list= processXML(startDir);
                            } 
        } catch (Exception e) {
            System.out.println(e);
        }
        return list;
    }
}

Edited 3 Years Ago by Nick Evan: Fixed formatting

This article has been dead for over six months. Start a new discussion instead.