Updating XML File using SAX Parser - java

I try to update XML file which was read from the database, saved as a XMLType and then i performed SAXParse saving in variables all information i needed to use to construct further queries to the database. Basing on the values I've read I'm checking some conditions and then I want to update values of 3 nodes. How can I update the values. Below is the code I use to parse document but I have no idea how to update XML file in java using SAX.
public void parseXML(int i) throws XMLParseException, SAXException, IOException, SQLException {
String xml = printXML(i);
saxParser.parse(new InputSource(new StringReader(xml)), handler);
}
And in handler i have various conditions to save things I'm interested in like:
public class UserHandler extends DefaultHandler {
StringBuilder builder = new StringBuilder();
private Data data = new Data();
boolean idOrder = false;
boolean idReader = false;
#Override
public void startElement(String uri,
String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equalsIgnoreCase("order")) {
data.setIdOrder(attributes.getValue("ID_ORDER"));
} else if (qName.equalsIgnoreCase("id_reader")) {
idReader = true;
}
builder.setLength(0);
}
#Override
public void endElement(String uri,
String localName, String qName) throws SAXException {
if (qName.equalsIgnoreCase("id_reader")) {
data.setIdReader(builder.toString());
}
}
#Override
public void characters(char ch[],
int start, int length) throws SAXException {
if (idReader) {
builder.append(new String(ch, start, length));
}
}
}
Please give me some hints.

Related

Java SAX is not parsing properly

I would appreciate any help on this.
This is my first handler I wrote.
I got I REST Webservice returning XML of links. It has quite simple structure and is not deep.
I wrote a handler for this:
public class SAXHandlerLnk extends DefaultHandler {
public List<Link> lnkList = new ArrayList();
Link lnk = null;
private StringBuilder content = new StringBuilder();
#Override
//Triggered when the start of tag is found.
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals("link")) {
lnk = new Link();
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("link")) {
lnkList.add(lnk);
}
else if (qName.equals("applicationCode")) {
lnk.applicationCode = content.toString();
}
else if (qName.equals("moduleCode")) {
lnk.moduleCode = content.toString();
}
else if (qName.equals("linkCode")) {
lnk.linkCode = content.toString();
}
else if (qName.equals("languageCode")) {
lnk.languageCode = content.toString();
}
else if (qName.equals("value")) {
lnk.value = content.toString();
}
else if (qName.equals("illustrationUrl")) {
lnk.illustrationUrl = content.toString();
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
content.append(ch, start, length);
}
}
Some XML returned can be empty eg. or . When this happens my handler unfortunatelly adds previous value to the Object lnk. So when is empty in XML, I got lnk.illustrationUrl = content; equal to lnk.value.
Link{applicationCode='onedownload', moduleCode='onedownload',...}
In the above example, I would like moduleCode to be empty or null, because in XML it is an empty tag.
Here is the calling class:
public class XMLRepositoryRestLinksFilterSAXParser {
public static void main(String[] args) throws Exception {
SAXParserFactory parserFactor = SAXParserFactory.newInstance();
SAXParser parser = parserFactor.newSAXParser();
SAXHandlerLnk handler = new SAXHandlerLnk();
parser.parse({URL}, handler);
for ( Link lnk : handler.lnkList){
System.out.println(lnk);
}
}
}
Like stated in my comment, you'd do the following. The callbacks are usually called in startElement, characters, (nested?), characters, endElement order, where (nested?) represents an optional repeat of the entire sequence.
#Override
//Triggered when the start of tag is found.
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
content = null;
if (qName.equals("link")) {
lnk = new Link();
}
}
Note that characters may be called multiple times per a single XML element in your document, so your current code might fail to capture all content. You'd be better off using a StringBuilder instead of a String object to hold your character content and append to it. See this answer for an example.

parsing xmll file through java

I am using SAXParse in java to parse an xml file. I was successfully able to do this with one of the files but I moved to second file and tried reading an attribute I kept getting null. I have thought of every possible cause I can but I am not able to figure it out.
Here's a sample of xml file:
<?xml version="1.0" encoding="UTF-8"?>
<ProcessorStatusCode/>
<StatusCode>E</StatusCode>
<ErrorNo>1852</ErrorNo>...
And here's my java code:
public class ReadXML
{
public static void main(String[] args) throws IOException,SAXException, ParserConfigurationeException
{
String OrderNum;
SAXParserFactory parser = SAXParserFactory.newInstance();
SAXParser Sparser = parser.newSAXParser();
ReadXML handler = new ReadXML();
Sparser.parse("ErrorDescription.xml",handler);
}
public void characters(char[] buffer,int start,int length)
{
temp = new String(buffer, start, length);
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
temp = " ";
if(qName.equalsIgnoreCase("ErrorNo"))
{
//transaction = new Transaction();
OrderNum = attributes.getValue(ErrorNo);
}
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
if(qName.equalsIgnoreCase("ErrorNo"))
{
System.out.println(OrderNum);
}
}
}//end of class
String OrderNum is declared as a local variable in the main() method, it should be a class member variable instead to be accessible in ReadXML.startElement().

How to get text of an element in xml with two attributes in java

I would like to get the text inside an element that has two attributes, the sample xml is as below
<?xml version="1.0" encoding="UTF-8"?>
<queries>
<query pagename="master" param="default">
SELECT * from test;
</query>
<query pagename="uftl" param="default">
SELECT uftl, lop from dwells where lop='a'
</query>
</queries>
Input: two attributes, output: the query. i.e, on giving the input as 'master','default' I would like to get the query for that element, in this case 'SELECT * from test;"
oh. i write dom parser while waiting your answer
private String parse(Document document) {
Element root = document.getDocumentElement();
NodeList queries = root.getElementsByTagName("queries");
int queriesLength = queries.getLength();
for (int i = 0; i < queriesLength; i++) {
Element currentQuery = (Element) queries.item(i);
if (currentQuery.getNodeType() == Element.ELEMENT_NODE) {
String pagename = currentQuery.getAttributes()
.getNamedItem("pagename").getTextContent();
String param = currentCategory.getAttributes()
.getNamedItem("param").getTextContent();
if(param.equals(paramValue) && pagename.equals(pagename)){
String query = currnetNode.item(0).getTextContent();
return query;
}
return null;
}
}
}
SAX parser:
public class parser implements ContentHandler {
boolean check = false;
ArrayList<String> queries = new ArrayList<>();
#Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
switch (localName) {
case "query":
String param = atts.getValue("param");
String pagename = atts.getValue("pagename");
check = true;
break;
default:
return;
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
check = false;
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
String tagContent = new String(ch, start, length).trim();
if(check){
if(!tagContent.isEmpty()){
queries.add(tagContent);
}
}
}
i delete sum overriden method because they was empty and unneccesary here. you must implement them and leave empty
UPDATE:
class main:
public class Main {
public static void main(String[] args) throws IOException, SAXException {
ArrayList<String> queries = new parser().getQueries("test.xml");
for (String query : queries){
System.out.println(query);
}
}
}
parser class:
public class parser implements ContentHandler {
boolean check = false;
ArrayList<String> queries = new ArrayList<>();
public ArrayList<String> getQueries(String fileName) throws SAXException, IOException {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(this);
xmlReader.parse(fileName);
return queries;
}
#Override
public void setDocumentLocator(Locator locator) {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void startDocument() throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void endDocument() throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void endPrefixMapping(String prefix) throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
switch (localName) {
case "query":
String param = atts.getValue("param");
String pagename = atts.getValue("pagename");
if(!param.isEmpty() && !pagename.isEmpty())
check = true;
break;
default:
return;
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
check = false;
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
String tagContent = new String(ch, start, length).trim();
if(check){
if(!tagContent.isEmpty()){
queries.add(tagContent);
}
}
}
#Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void processingInstruction(String target, String data) throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
#Override
public void skippedEntity(String name) throws SAXException {
//To change body of implemented methods use File | Settings | File Templates.
}
}
also I add xml file in root of project with te name test.xml
my output look like this:
SELECT * from test;
SELECT uftl, lop from dwells where lop='a'
Below is an example of how you could implement this use case using the javax.xml.xpath APIs in the JDK/JRE.
import javax.xml.namespace.QName;
import javax.xml.xpath.*;
import org.xml.sax.InputSource;
public class Demo {
public static void main(String[] args) throws Exception {
// Your query can be expressed as the following XPath. It contains to
// variables $pagename and $param that we can use to inject different
// values into.
String expression = "/queries/query[#pagename=$pagename and #param=$param]";
XPathFactory xpf = XPathFactory.newInstance();
XPath xPath = xpf.newXPath();
// We will use an instance of `XPathVariableResolver` to put the real
// values into our XPath expression
xPath.setXPathVariableResolver(new XPathVariableResolver() {
#Override
public Object resolveVariable(QName variableName) {
if("pagename".equals(variableName.getLocalPart())) {
return "master";
} else if("param".equals(variableName.getLocalPart())) {
return "default";
}
return null;
}
});
InputSource source = new InputSource("src/forum14825994/input.xml");
// When we execute the XPath we can ask that the result be returned to
// us as a String
String result = (String) xPath.evaluate(expression, source, XPathConstants.STRING);
System.out.println(result);
}
}
Output
SELECT * from test;

Reading nested tags with sax parser

i am trying to read a xml file with following tag, but the sax parser is unable to read nested tags like
<active-prod-ownership>
<ActiveProdOwnership>
<Product code="3N3" component="TRI_SCORE" orderNumber="1-77305469" />
</ActiveProdOwnership>
</active-prod-ownership>
here is the code i am using
public class LoginConsumerResponseParser extends DefaultHandler {
// ===========================================================
// Fields
// ===========================================================
static String str="default";
private boolean in_errorCode=false;
private boolean in_Ack=false;
private boolean in_activeProdOwnership= false;
private boolean in_consumerId= false;
private boolean in_consumerAccToken=false;
public void startDocument() throws SAXException {
Log.e("i am ","in start document");
}
public void endDocument() throws SAXException {
// Nothing to do
Log.e("doc read", " ends here");
}
/** Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">*/
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
if(localName.equals("ack")){
in_Ack=true;
}
if(localName.equals("error-code")){
in_errorCode=true;
}
if(localName.equals("active-prod-ownership")){
Log.e("in", "active product ownership");
in_activeProdOwnership=true;
}
if(localName.equals("consumer-id")){
in_consumerId= true;
}
if(localName.equals("consumer-access-token"))
{
in_consumerAccToken= true;
}
}
/** Gets be called on closing tags like:
* </tag> */
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if(localName.equals("ack")){
in_Ack=false;
}
if(localName.equals("error-code")){
in_errorCode=false;
}
if(localName.equals("active-prod-ownership")){
in_activeProdOwnership=false;
}
if(localName.equals("consumer-id")){
in_consumerId= false;
}
if(localName.equals("consumer-access-token"))
{
in_consumerAccToken= false;
}
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
public void characters(char ch[], int start, int length) {
if(in_Ack){
str= new String(ch,start,length);
}
if(str.equalsIgnoreCase("success")){
if(in_consumerId){
}
if(in_consumerAccToken){
}
if(in_activeProdOwnership){
str= new String(ch,start,length);
Log.e("active prod",str);
}
}
}
}
but on reaching the tag in_activeProdOwnersip read only "<" as the contents of the tag
please help i need to the whole data to be read
The tags in your XML file and parser does not match. I think you are mixing-up tags with attribute names. Here is the code that correctly parses your sample XML:
public class LoginConsumerResponseParser extends DefaultHandler {
public void startDocument() throws SAXException {
System.out.println("startDocument()");
}
public void endDocument() throws SAXException {
System.out.println("endDocument()");
}
public void startElement(String namespaceURI, String localName,
String qName, Attributes attrs)
throws SAXException {
if (qName.equals("ActiveProdOwnership")) {
inActiveProdOwnership = true;
} else if (qName.equals("Product")) {
if (!inActiveProdOwnership) {
throw new SAXException("Product tag not expected here.");
}
int length = attrs.getLength();
for (int i=0; i<length; i++) {
String name = attrs.getQName(i);
System.out.print(name + ": ");
String value = attrs.getValue(i);
System.out.println(value);
}
}
}
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("ActiveProdOwnership"))
inActiveProdOwnership = false;
}
public void characters(char ch[], int start, int length) {
}
public static void main(String args[]) throws Exception {
String xmlFile = args[0];
File file = new File(xmlFile);
if (file.exists()) {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
DefaultHandler handler = new Test();
parser.parse(xmlFile, handler);
}
else {
System.out.println("File not found!");
}
}
private boolean inActiveProdOwnership = false;
}
A sample run will produce the following output:
startDocument()
code: 3N3
component: TRI_SCORE
orderNumber: 1-77305469
endDocument()
I suspect this is what's going wrong:
new String(ch,start,length);
Here, you're passing a char[] to the String constructor, but the constructor is supposed to take a byte[]. The end result is you get a mangled String.
I suggest instead that you make the str field a StringBuilder, not a String, and then use this:
builder.append(ch,start,length);
You then need to clear the StringBuilder each time startElement() is called.

How to adjust my code to this situation for SAX XML parsing in Android

On advice on someone here on Stackoverflow I changed my method of parsing to the SAXParser.
Thanks to different tutorials I'm able to get it to work, and I have to say that it does work faster (which is very important for my app).
The problem, however, is that my XML file goes deeper than the tutorial's example XML's I've seen.
This a sample of my XML file:
<Message>
<Service>servicename</Service>
<Insurances>
<BreakdownInsurance>
<Name>Insurance name</Name>
<InsuranceNR/>
<LicenseNr/>
</BreakdownInsurance>
<CarDamageInsurance>
<Name>Insurance name 2</Name>
<InsuranceNR></InsuranceNR>
</CarDamageInsurance>
</Insurances>
<Personal>
<Name>my name</Name>
</Personal>
</Message>
I can get the personal details like name, but my code doesn't seem to work with the insurances. I think this is because it's one node more.
This is the code I'm using in my Handler class:
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
currentElement = true;
if (localName.equals("Message")) {
geg = new GegevensXML();
}
}
#Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
currentElement = false;
/********** Autopech **********/
if (localName.equals("Name")) {
geg.setAutopechMaatschappij(currentValue);
}
else if (localName.equals("InsuranceNR")){
geg.setAutopechPolis(currentValue);
}
else if (localName.equals("LicenseNr")){
geg.setAutopechKenteken(currentValue);
}
#Override
public void characters(char ch[], int start, int length) {
if (currentElement) {
currentValue = new String(ch, start, length);
currentElement = false;
}
So how must I adjust it?
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
currentElement = true;
if (localName.equals("Message")) {
geg = new GegevensXML();
}
if(localName.equals("BreakdownInsurance"))
{
BreakdownInsurance = true;
}
}
#Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
currentElement = false;
/********** Autopech **********/
if (localName.equals("Name"))
{
if(BreakdownInsurance)
{
geg.setBreakdownInsuranceName(currentValue);
BreakdownInsurance = false;
}
else
{
geg.setAutopechMaatschappij(currentValue);
}
}
else if (localName.equals("InsuranceNR")){
geg.setAutopechPolis(currentValue);
}
else if (localName.equals("LicenseNr")){
geg.setAutopechKenteken(currentValue);
}
Similarly do it for other cases... 'BreakdownInsurance' is a boolean. use it as a Flag...
The depth should not be a problem. I have more levels and the exact code works fine for me. Could it be that you have several nodes with the same name? "Name" in Personal, and "Name" in those insurances nodes?
Just modify the endElement()...
Add Flags to indicate where current Name is to be saved since you are having Name coming under both <BreakdownInsurance>
and <Personal>.

Categories