1

XML file cant able to parse when it contains "&&" in node's attribute value.

XML file :

<?xml version="1.0" encoding="UTF-8" ?>
<test version="0.0.3" >
    <SFTP ipaddress="12.12.12.12" port="22" uname="abc" pwd="abc&&" path="/testdev" />
</test>

when is used pwd="abc&&" at that time it gives me error like this, If i will not used special characters than its working fine.

Error :

At line 3, column 62: not well-formed (invalid token)
    org.apache.harmony.xml.ExpatParser$ParseException: At line 3, column 62: not well-formed (invalid token)
    at org.apache.harmony.xml.ExpatParser.parseFragment(ExpatParser.java:515)
    at org.apache.harmony.xml.ExpatParser.parseDocument(ExpatParser.java:474)
    at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:321)
    at org.apache.harmony.xml.ExpatReader.parse(ExpatReader.java:279)
    at com.test.bl.ConfigurationParser.parseFile(ConfigurationParser.java:61)
    at com.test.ui.LoginActivity$ConfigurationXMLParseOperation.doInBackground(LoginActivity.java:209)
    at com.test.ui.LoginActivity$ConfigurationXMLParseOperation.doInBackground(LoginActivity.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:287)
    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    at java.lang.Thread.run(Thread.java:856)

Code :

public void parseFile(final InputStream inputStream) throws ParserConfigurationException,
        SAXException, IOException {
    try {
        final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        final SAXParser saxParser = saxParserFactory.newSAXParser();
        final XMLReader xmlReader = saxParser.getXMLReader();
        xmlReader.setContentHandler(this);
        xmlReader.parse(new InputSource(inputStream));
    } catch (ParserConfigurationException e) {
        Logger.e(TAG, e.getMessage(), e);
    } catch (SAXException e) {
        Logger.e(TAG, e.getMessage(), e);
    } catch (IOException e) {
        Logger.e(TAG, e.getMessage(), e);
    }
}


@Override
public void startElement(final String uri, final String localName, final String qName,
        final Attributes attributes) throws SAXException {
    mElementStart = true;
    if (localName.equals(null)) {
        Logger.i(TAG, "Devices xml file is empty");
    }
    tempValue = "";
    if (localName.equalsIgnoreCase(mSFTPParseNodeString)) {
        sftpConfiguration = new SFTPConfiguration();

        sftpConfiguration.mSftpIp = attributes.getValue(mSFTPIpParseNodeString);

        sftpConfiguration.mRemotePath = attributes.getValue(mSFTPPathParseNodeString);

        sftpConfiguration.mSftpPort = Integer.parseInt(attributes
                .getValue(mSFTPPortParseNodeString));

        sftpConfiguration.mUserName = attributes.getValue(mSFTPUserNameParseNodeString);

        sftpConfiguration.mUserPassword = attributes.getValue(mSFTPPasswordParseNodeString);
    }

}

Please help me and give me solution how can i parse this value and use in my code.

Thanks

sam_k
  • 5,983
  • 14
  • 76
  • 110
  • 3
    In XML "&" MUST be encoded as "&". – OcuS Jun 06 '13 at 16:06
  • You should encode all of your values using an XML or HTML encode function. I wouldn't recommend just correcting the & value, as their are several others such as <, >, &, '. Check out this wiki link to see the different types of characters and escape sequences for XML and HTML: http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references – Kyle Jun 06 '13 at 16:08
  • See [which characters are invalid unless encoded in an xml attribute](http://stackoverflow.com/questions/866706/which-characters-are-invalid-unless-encoded-in-an-xml-attribute) – flup Jun 06 '13 at 16:09

3 Answers3

5

In XML all & characters must be encoded as &amp;.

So from wherever your file come, you have to change those characters before even trying to parse the XML.

Same for:

  • < as &lt;
  • > as &gt;

See List of XML and HTML character entity references.

OcuS
  • 5,320
  • 3
  • 36
  • 45
  • thanks for your answer. but how can i use this `'&'` character in password field after parsing. – sam_k Jun 06 '13 at 16:21
  • Your input should be escaped from all special characters. If you are creating this XML file manually to be used by an application, you will need to escape all the special characters manually and then have your code that parses the file decode all of the text before it uses any of it. This is a fairly simple process, check out the StringEscapeUtils class from the apache commons. http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringEscapeUtils.html If the generated XML is coming from another application, that application should encode all the values. – Kyle Jun 06 '13 at 16:26
  • I added `&amp` in my file instead of `&` but its not working. My xml file is manually. What i have to do – sam_k Jun 06 '13 at 16:28
  • Just to clarify, it should be `&` it will need a semicolon. You can use StringEscapeUtils by calling `StringEscapeUtils.unescapeXml(yourStringToDecode);` – Kyle Jun 06 '13 at 16:34
4

XML has five special characters which have special treatment by the XML parser:

  1. < the start of a tag.
  2. > the end of a tag.
  3. " the start and end of an attribute value.
  4. ' the alternative start and end of an attribute value.
  5. & the start of an entity (which ends with ;).

Hence you have to replace the '&' character with '&amp;' or else you can replace it with appending it to the Unicode decimal equivalent '&#38;' before parsing it. Please take a look at the below example for better understanding:

First, we can create a Model to represent the data in your XML file:

package com.stackoverflow.xml.parser.service;

/**
 * @author sarath_sivan
 */
public class SFTPConfiguration {

    private String ipAddress;
    private int port;
    private String userName;
    private String password;
    private String path;

    public SFTPConfiguration() {}

    public SFTPConfiguration(String ipAddress, int port, 
            String userName, String password, String path) {
        this.ipAddress = ipAddress;
        this.port = port;
        this.userName = userName;
        this.password = password;
        this.path = path;
    }

    public String getIpAddress() {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress) {
        this.ipAddress = ipAddress;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String toString() {
        StringBuffer sftpConfigBuilder = new StringBuffer();
        sftpConfigBuilder.append("SFTP Configuration Details > ");
        sftpConfigBuilder.append("IP Address: ").append(getIpAddress()).append(", ");
        sftpConfigBuilder.append("Port: ").append(getPort()).append(", ");
        sftpConfigBuilder.append("UserName: ").append(getUserName()).append(", ");
        sftpConfigBuilder.append("Password: ").append(getPassword()).append(", ");
        sftpConfigBuilder.append("Path: ").append(getPath());
        return sftpConfigBuilder.toString();
    }

}

Now, you can implement the SAX Parser as shown below:

package com.stackoverflow.xml.parser.service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.io.FileUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author sarath_sivan
 */
public class SFTPConfigHandler extends DefaultHandler {

    private SFTPConfiguration sftpConfiguration;
    private String configData;

    public void characters(char[] buffer, int start, int length) {
        configData = new String(buffer, start, length);
    }

    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        configData = "";
        if (qName.equalsIgnoreCase("SFTP")) {
            sftpConfiguration = new SFTPConfiguration();
            sftpConfiguration.setIpAddress(attributes.getValue("ipaddress"));
            sftpConfiguration.setPort(Integer.parseInt(attributes.getValue("port")));
            sftpConfiguration.setUserName(attributes.getValue("uname"));
            sftpConfiguration.setPassword(attributes.getValue("pwd"));
            sftpConfiguration.setPath(attributes.getValue("path"));
        }
    }

    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        //do something if required.
    }

    public SFTPConfiguration getSFTPConfiguration() {
        return sftpConfiguration;
    }

    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory saxParserFactory  = SAXParserFactory.newInstance();
        SAXParser saxParser  = saxParserFactory.newSAXParser();
        SFTPConfigHandler sftpConfigHandler = new SFTPConfigHandler();
        String strXml = FileUtils.readFileToString(new File("C:/Users/sarath_sivan/Desktop/sftp-config.xml"));
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(strXml.replaceAll("&", "&amp;").getBytes("UTF-8"));
        saxParser.parse(byteArrayInputStream, sftpConfigHandler);
        System.out.println(sftpConfigHandler.getSFTPConfiguration().toString());
    }
}

OUTPUT:

SFTP Configuration Details > IP Address: 12.12.12.12, Port: 22, UserName: abc, Password: abc&&, Path: /quipmentdev

Hope this helps... Thank you!

1218985
  • 7,531
  • 2
  • 25
  • 31
0

You need to escape it as &amp

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136