Modify xml attributes values using XmlPullParser

1.4k Views Asked by At

I have an XML (actually a String) and I want to find all tags which contain attributes width and height and to modify their values.

XML example:

<div>
<div class="separator" style="clear: both; text-align: center;">
    <a href="http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinU3232I/AAAAAAAADZU332/zq3apERWFms/s800/IMG_3426.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;">
        <img border="0" height="426" src="http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinUI/AAAAAAAADZU/zq32323apERWFms/s800/IMG_3426.JPG" width="640" />
    </a>
</div>
<div class="separator" style="clear: both; text-align: center;">
    <iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/sI9Qf7UmXl0" width="420"></iframe>
</div>

In the above example I want to modify:

  • 426 and 640 values
  • 560 and 315 values

I was able to identify some of the values using XmlPullParser: the code below identifies 426 and 640 values, but not 560 and 315. Also I do not know how to modify them in XML:

public void parse(String inputString) throws XmlPullParserException, IOException {
    XmlPullParser parser = Xml.newPullParser();
    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
    parser.setInput(new StringReader(inputString));
    parser.nextTag();
    readXml(parser);
}

private void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
    int eventType = parser.getEventType();
    while (eventType != XmlPullParser.END_DOCUMENT) {
        switch (eventType) {
            case XmlPullParser.START_TAG:
                break;

            case XmlPullParser.END_TAG:
                String h = parser.getAttributeValue(null, "height");
                String w = parser.getAttributeValue(null, "width");
                if (!TextUtils.isEmpty(h) && !TextUtils.isEmpty(w)) {
                    // TODO: need to change here h and w values in XML
                }
                break;
        }
        eventType = parser.next();
    }
}
2

There are 2 best solutions below

1
Алексей Мальченко On

XmlPullParser can not modify values. You need parse and write at same time. Use DomDocument or stream based readers and writers at same time.

DomDocument the best for you.

2
Ankur Aggarwal On

Here is the required solution. I wrote this in JAVA, but you can use it in android with minor changes. Since you did not write what change you wanted to make to the file, I assumed multiplication by 2, but you can change that as well:

private static Document doc = null;
public static void main(String[] args) {
    try {   
        String s = "<File>\n" +
                "<div class=\"separator\" style=\"clear: both; text-align: center;\">\n" +
                "    <a href=\"http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinU3232I/AAAAAAAADZU332/zq3apERWFms/s800/IMG_3426.JPG\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\">\n" +
                "        <img border=\"0\" height=\"426\" src=\"http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinUI/AAAAAAAADZU/zq32323apERWFms/s800/IMG_3426.JPG\" width=\"640\" />\n" +
                "    </a>\n" +
                "</div>\n" +
                "<div class=\"separator\" style=\"clear: both; text-align: center;\">\n" +
                "    <iframe allowfullscreen=\"\" frameborder=\"0\" height=\"315\" src=\"https://www.youtube.com/embed/sI9Qf7UmXl0\" width=\"420\"></iframe>\n" +
                "</div>\n" +
                "</File>";
         InputStream stream = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
         DocumentBuilderFactory dbFactory 
            = DocumentBuilderFactory.newInstance();
         DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();

         doc = dBuilder.parse(stream);
         doc.getDocumentElement().normalize();

         Element root = doc.getDocumentElement();

         //First, browse the children and modify the required attributes
         browseChildNodesAndModifyValue(root);

         //Now, write to a file, or do something with it
         writeDomToFile();

      } catch (Exception e) {
         e.printStackTrace();
      }


}

private static void browseChildNodesAndModifyValue(Node parent){
    NodeList nodeList = parent.getChildNodes();

    if(nodeList.getLength() > 0){
        for(int temp = 0; temp< nodeList.getLength(); temp++){
            Node node = nodeList.item(temp);
            browseChildNodesAndModifyValue(node);
        }
    }else{
        NamedNodeMap nodeMap = parent.getAttributes();

        if(nodeMap == null) return;

        for(int temp2=0; temp2< nodeMap.getLength(); temp2++){
            Node n = nodeMap.item(temp2);
            String attributeName = n.getNodeName();

            if(attributeName.equals("height")){
                int height = Integer.parseInt(n.getNodeValue());
                System.out.println("Height = "+height);

                //Modify the height here. e.g. I will multiply by 2
                n.setNodeValue(String.valueOf(height*2));
            }else if(attributeName.equals("width")){
                int width = Integer.parseInt(n.getNodeValue());
                System.out.println("width = "+width);

                //Modify the width here. e.g. I will multiply by 2
                n.setNodeValue(String.valueOf(width*2));
            }

        }
    }
}

private static void writeDomToFile() throws TransformerException{
    TransformerFactory transformerfactory=
            TransformerFactory.newInstance();
    Transformer transformer=
            transformerfactory.newTransformer();

    DOMSource source=new DOMSource(doc);

    StreamResult result=new StreamResult(new File("C:\\abc.xml"));

    /*
     * For Android, you can use this :

        FileOutputStream _stream=getApplicationContext().openFileOutput("NewDom.xml", getApplicationContext().MODE_WORLD_WRITEABLE);
        StreamResult result=new StreamResult(_stream);

     */

    transformer.transform(source, result);
}

And the output file which I received was:

<File>
<div class="separator" style="clear: both; text-align: center;">
    <a href="http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinU3232I/AAAAAAAADZU332/zq3apERWFms/s800/IMG_3426.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;">
        <img border="0" height="852" src="http://1.bp.blogspot.com/-b5iKjQ5ivZQ/VOoBX9NinUI/AAAAAAAADZU/zq32323apERWFms/s800/IMG_3426.JPG" width="1280"/>
    </a>
</div>
<div class="separator" style="clear: both; text-align: center;">
    <iframe allowfullscreen="" frameborder="0" height="630" src="https://www.youtube.com/embed/sI9Qf7UmXl0" width="840"/>
</div>
</File>