Search code examples
javaxmlparsingsax

How to add node a structured xml at particular location from java


Need help on how to add an xml node at a desired position in the xml.

For Example:

Original xml

<Errors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="errors.xsd">
    <Service Name="SYSTEM" Range="0-0299">
        <Type Name="System">
            <Error Name="ERROR1">
                <Code>0001</Code>
                <Description>error1</Description>
            </Error>
            <Error Name="ERROR_OTHER">
            <Code>0</Code>
            <Description>error error</Description>
        </Error>
        <Error Name="ERROR2">
            <Code>0002</Code>
            <Description>error2</Description>
        </Error>
    </Type>
    <Type Name="Security">
        <Error Name="ERROR3">
            <Code>0300</Code>
            <Description>error3</Description>
        </Error>
        <Error Name="ERROR4">
            <Code>0301</Code>
            <Description>error4</Description>
        </Error>
    </Type>
    </Service>
    <Service Name="WEBSVC" Range="1000-1199">
    <Type Name="Data">
        <Error Name="ERROR10">
            <Code>1000</Code>
            <Description>error10</Description>
        </Error>
        <Error Name="ERROR5">
            <Code>1001</Code>
            <Description>error5</Description>
        </Error>
        <Error Name="ERROR6">
            <Code>1004</Code>
            <Description>desc</Description>
        </Error>
    </Type>
    <Type Name="System">
        <Error Name="ERROR7">
            <Code>1200</Code>
            <Description>xyz123</Description>
        </Error>
        <Error Name="ERROR8">
            <Code>1201</Code>
            <Description>abcd</Description>
        </Error>
    </Type>
    <Type Name="Business">
        <Error Name="ERROR9">
            <Code>1400</Code>
            <Description>rrreerer</Description>
        </Error>
        <Error Name="ERROR10">
            <Code>1401</Code>
            <Description>err</Description>
        </Error>
    </Type>
    </Service>
</Errors>

My requirement is to add:

        <Error Name="ERROR_NEW">
            <Code>03019</Code>
            <Description>This is a new error</Description>
        </Error>

At location for example Errors/Service Name="WEBSVC"/Type Name="System". This may vary as per the requirement.

Desired xml

<Errors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="errors.xsd">
    <Service Name="SYSTEM" Range="0-0299">
        <Type Name="System">
            <Error Name="ERROR1">
                <Code>0001</Code>
                <Description>error1</Description>
            </Error>
            <Error Name="ERROR_OTHER">
            <Code>0</Code>
            <Description>error error</Description>
        </Error>
        <Error Name="ERROR2">
            <Code>0002</Code>
            <Description>error2</Description>
        </Error>
    </Type>
    <Type Name="Security">
        <Error Name="ERROR3">
            <Code>0300</Code>
            <Description>error3</Description>
        </Error>
        <Error Name="ERROR4">
            <Code>0301</Code>
            <Description>error4</Description>
        </Error>
    </Type>
    </Service>
    <Service Name="WEBSVC" Range="1000-1199">
    <Type Name="Data">
        <Error Name="ERROR10">
            <Code>1000</Code>
            <Description>error10</Description>
        </Error>
        <Error Name="ERROR5">
            <Code>1001</Code>
            <Description>error5</Description>
        </Error>
        <Error Name="ERROR6">
            <Code>1004</Code>
            <Description>desc</Description>
        </Error>
    </Type>
    <Type Name="System">
        <Error Name="ERROR7">
            <Code>1200</Code>
            <Description>xyz123</Description>
        </Error>
        <Error Name="ERROR8">
            <Code>1201</Code>
            <Description>abcd</Description>
        </Error>
        **<Error Name="ERROR_NEW">
            <Code>03019</Code>
            <Description>This is a new error</Description>
        </Error>**
    </Type>
    <Type Name="Business">
        <Error Name="ERROR9">
            <Code>1400</Code>
            <Description>rrreerer</Description>
        </Error>
        <Error Name="ERROR10">
            <Code>1401</Code>
            <Description>err</Description>
        </Error>
    </Type>
    </Service>
</Errors>

I am using SAX parser and I am able the parse the document successfully.

ErrorHandler.java

package com.browser.main.Handler;



import java.util.ArrayList;

import java.util.List;



import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;



import com.browser.main.model.*;





public class ErrorHandler extends DefaultHandler {



    private List<ErrorService> errorServiceList = null;

    private ErrorService errorService = null;

    private List<ErrorType> errorTypeList = null;

    private ErrorType errorType = null;

    private List<ErrorDetails> errorDetailList = null;

    private ErrorDetails errorDetails = null;





    public List<ErrorService> getErrorServiceList() {

    return errorServiceList;

    }



    boolean bService = false;

    boolean bType = false;

    boolean bError = false;

    boolean bCode = false;

    boolean bDesc = false;



    @Override

    public void startElement(String uri, String localName, String qName, Attributes attributes)

        throws SAXException {



    if (qName.equalsIgnoreCase("Service")) {

        errorService = new ErrorService();

        errorService.setServiceName(attributes.getValue("Name"));

        if(errorServiceList == null){

            errorServiceList = new ArrayList<ErrorService>();

        }

    } else if (qName.equalsIgnoreCase("Type")){

        errorType = new ErrorType();

        errorType.setErrorTypeName(attributes.getValue("Name"));

        if(errorTypeList == null){

            errorTypeList = new ArrayList<ErrorType>();

        }

    } else if (qName.equalsIgnoreCase("Error")){

        errorDetails = new ErrorDetails();

        errorDetails.setErrorName(attributes.getValue("Name"));

        if(errorDetailList == null){

            errorDetailList = new ArrayList<ErrorDetails>();

        }

    } else if (qName.equalsIgnoreCase("Code")){

        bCode = true;

    } else if (qName.equalsIgnoreCase("Description")){

        bDesc = true;

    }





    }





    @Override

    public void endElement(String uri, String localName, String qName) throws SAXException {

    if (qName.equalsIgnoreCase("Error")) {

        errorDetailList.add(errorDetails);

    } else if (qName.equalsIgnoreCase("Type")){

        errorType.setErrorsDetailList(errorDetailList);

        errorDetailList = null;

        errorTypeList.add(errorType);

    } else if (qName.equalsIgnoreCase("Service")){

        errorService.setErrorTypeList(errorTypeList);

        errorTypeList = null;

        errorServiceList.add(errorService);

    }

    }





    @Override

    public void characters(char ch[], int start, int length) throws SAXException {



    if (bCode) {

        errorDetails.setErrorCode(new String(ch, start, length));

        bCode = false;

    } else if (bDesc) {

        errorDetails.setErrorDesc(new String(ch, start, length));

        bDesc = false;

    }

    }

}

BrowserMain.java

package com.browser.main;



import java.io.File;

import java.io.IOException;

import java.util.List;



import javax.xml.parsers.ParserConfigurationException;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;



import org.xml.sax.SAXException;



import com.browser.main.Handler.ErrorHandler;

import com.browser.main.model.*;



public class BrowserMain {



    /**

     * @param args

     */

    public static void main(String[] args) {



        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

        try {

        SAXParser saxParser = saxParserFactory.newSAXParser();

        ErrorHandler handler = new ErrorHandler();

        saxParser.parse(new File("/uapi-error-en.xml"), handler);

        List<ErrorService> errorServiceList = handler.getErrorServiceList();

        System.out.println(errorServiceList.size());

        } catch (ParserConfigurationException | SAXException | IOException e) {

        e.printStackTrace();

        }
    }
}

Please suggest me how reach to the desired position and add the node there. Thanks in advance.


Solution

  • Got the answer. Used DOM parser.

    public class XmlAppend {
    
    public static void main(String[] args) {
        try {
            File xmlFile = new File("G:/workspace/UAPIErrorBrowser/uapi-error-en.xml");
            //Create the documentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //Create the documentBuilder
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //Create the Document  by parsing the file
            Document document = documentBuilder.parse(xmlFile);
            //Get the root element of the xml Document;
            Element documentElement = document.getDocumentElement();
            System.out.println("documentElement:" + documentElement.toString());
    
            boolean isElement = false; 
    
    
            while(!isElement){
                NodeList allTypes =  documentElement.getElementsByTagName("Type");//("Errors");
                   for(int i = 0; i < allTypes.getLength(); i++){
                       Node type = allTypes.item(i);
                       if(type.getAttributes().getNamedItem("Name").getTextContent().equalsIgnoreCase("System") && type.getParentNode().getAttributes().getNamedItem("Name").getTextContent().equalsIgnoreCase("WEBSVC")){
                           Element codeElement = document.createElement("Code");
                           codeElement.setTextContent("3200");
    
                           Element descElement = document.createElement("Description");
                           descElement.setTextContent("this is awesome");
    
                           Element errorNode = document.createElement("Error");
                           errorNode.setAttribute("Name", "THIS_IS_GREAT");
    
                           errorNode.appendChild(codeElement);
                           errorNode.appendChild(descElement);
    
                           type.appendChild(errorNode);
                           isElement = true;
                           break;
                       }
    
    
                   }
    
               //if(documentElement.getChildNodes())
           }
    
            Transformer tFormer = TransformerFactory.newInstance().newTransformer();
    //  Set output file to xml
            tFormer.setOutputProperty(OutputKeys.METHOD, "xml");
    //  Write the document back to the file
            Source source = new DOMSource(document);
            Result result = new StreamResult(xmlFile);
            tFormer.transform(source, result);
    
    
        } catch (TransformerException ex) {
            Logger.getLogger(XmlAppend.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(XmlAppend.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(XmlAppend.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(XmlAppend.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    }