This XML of yours has a basic problem, which is to have more than one root tag (<Registos />
and <Socios />
), making it an invalid XML. Since it is not a valid format you will not be able to read it with DOM, because it expects a valid XML, then an error similar to this should occur:
[Fatal Error] :4:2: The markup in the document following the root element must be well-formed.
lineNumber: 4; columnNumber: 2; The markup in the document following the root element must be well-formed.
The correct thing is that you already expect a well-formed XML, as suggested at the end of this answer. If this is beyond what you can do, if it is delivered by some other application that you do not own, as in a third-party integration, then you will have to bypass it by adjusting the received XML. The suggestion is to form a valid XML from what you receive, including any root tag. I will use <Data />
as an example.
Our code to transform XML into a valid format will look something like this:
private static final String DATA_ROOT_START = "<Data>";
private static final byte[] DATA_ROOT_START_BYTES = DATA_ROOT_START.getBytes();
private static final String DATA_ROOT_END = "</Data>";
private static final byte[] DATA_ROOT_END_BYTES = DATA_ROOT_END.getBytes();
private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
private static final byte[] XML_HEADER_BYTES = XML_HEADER.getBytes();
private static final int XML_HEADER_LENGTH = XML_HEADER.length();
public InputStream fixXML(final InputStream is) throws Exception {
try (final InputStream startIS = new ByteArrayInputStream(DATA_ROOT_START_BYTES);
final InputStream headerIS = new ByteArrayInputStream(XML_HEADER_BYTES);
final InputStream endIS = new ByteArrayInputStream(DATA_ROOT_END_BYTES)) {
is.skip(XML_HEADER_LENGTH);
final List<InputStream> streams = Arrays.asList(headerIS, startIS, is, endIS);
return new SequenceInputStream(Collections.enumeration(streams));
}
}
This guy recovers the InputStream
the contents of your XML, without the header. including the root tag we have chosen and also the header (this is not required in certain cases).
Once fixed we can read the XML, something like that:
final AssetManager manager = getAssets();
final InputStream is = manager.open("socios.xml");
final InputStream fixedXMLIS = fixXML(is);
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = factory.newDocumentBuilder();
final InputSource inputSource = new InputSource(fixedXMLIS);
final Document document = db.parse(inputSource);
final NodeList socios = document.getElementsByTagName("Socios");
final int sociosSize = socios.getLength();
for (int i = 0; i < sociosSize; i++) {
final Node socio = socios.item(i);
final NodeList socioChilds = socio.getChildNodes();
final int socioChildsSize = socioChilds.getLength();
for (int j = 0; j < socioChildsSize; j++) {
final Node e = socioChilds.item(j);
Log.d("XMLFIXSample", e.getTextContent().trim());
}
}
This will generate something like this:
I/XMLFIXSample(N): 1
I/XMLFIXSample(N): Paulo
I/XMLFIXSample(N): [email protected]
I/XMLFIXSample(N): 2
I/XMLFIXSample(N): Vitor
I/XMLFIXSample(N): [email protected]
I/XMLFIXSample(N): 3
I/XMLFIXSample(N): Rute
I/XMLFIXSample(N): [email protected]
After this you use the values as you need, filling directly some field on the screen, entity, etc.
Obs.: this code is an example that transforms XML into a valid format, adapts it and improves it as your needs, realize that it uses things from Java7, so if you want to use it like this, configure the target
to compile for a version that Android supports ;)
Obs2.: I don’t know if you are generating this XML, but if it is, consider putting it in a valid format, with just a root node, something like this:
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Registos>3</Registos>
<Socios>
<id>1</id>
<nome>Paulo</nome>
<email>[email protected]</email>
<id>2</id>
<nome>Vitor</nome>
<email>[email protected]</email>
<id>3</id>
<nome>Rute</nome>
<email>[email protected]</email>
</Socios>
</Data>
Another thing you can do is have a root tag for the partner data, something like that:
<Socio>
<id>1</id>
<nome>Paulo</nome>
<email>[email protected]</email>
</Socio>
Generating this final result:
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Registos>3</Registos>
<Socios>
<Socio>
<id>1</id>
<nome>Paulo</nome>
<email>[email protected]</email>
</Socio>
<Socio>
<id>2</id>
<nome>Vitor</nome>
<email>[email protected]</email>
</Socio>
<Socio>
<id>3</id>
<nome>Rute</nome>
<email>[email protected]</email>
</Socio>
</Socios>
</Data>
This would make it even simpler to work with XML
Bruno César, thank you for your reply. My "socios.xml" file is in Sdcard0, but I’m not getting the "final Inputstream is = manager.open(arquivoXML );" line to find the XML file. I have the reading permission "READ_EXTERNAL_STORAGE" and the following configuration: File Sdcardroot = Environment.getExternalStorageDirectory(); File arquivoXML = new File(Sdcardroot, "socios.xml");?
– Vitor Mendanha
@Vitormendanha there is already something else, maybe you better ask another question, if you need. Before researching here on Sopt on the subject, there are some questions, as this
– Bruno César
I was able to solve the problem: Replace the line "final Inputstream is = manager.open("socios.xml");" with "Inputstream is = new Bufferedinputstream(new Fileinputstream(arquivoXML ));".
– Vitor Mendanha
@Vitormendanha this is it :)
– Bruno César