I have an XML and inside it I want to modify for specific nodes the value of link attribute using SAXParser.
I did found https://stackoverflow.com/a/51662488/9681353 and I used Attributes2Impl for my case.
What I have so far:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
UpdateLinksHandler linksHandler = new UpdateLinksHandler();
saxParser.parse(xml, linksHandler);
#Override
public void startElement(String uri, String key, String qName, Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase(USEROBJECT)) {
String link = attributes.getValue("link");
if (link != null) {
Attributes2 attrs = (Attributes2) attributes;
Attributes2Impl newAttrs = new Attributes2Impl();
for (int i = 0; i < attrs.getLength(); i++) {
if (attrs.isSpecified(i)) {
String type = attrs.getType(i);
String value = attrs.getValue(i);
String name = attrs.getQName(i);
if (name == "link") {
value = modifyLink(value);
}
newAttrs.addAttribute(null, null, name, type, modifyLink(value));
}
}
super.startElement(uri, key, qName, newAttrs);
}
}
But I don't know if my approach is correct or how I should get my modified xml. Or SAXParser is just for reading purposes?
Thanks
Related
I have a simple xml and want to retrieve the value held in the 'String' which is either True or False. There are lots of suggested methods which look very complex! What would be the best way to do this?
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">"True"</string>
I am able to read the xml into an xmlReader as below.
XMLReader xmlReader = SAXParserFactory.newInstance()
.newSAXParser().getXMLReader();
InputSource source = new InputSource(new StringReader(response.toString()));
xmlReader.parse(source);
How would I now get the value out of the reader?
You will first need to define a Handler :
public class MyElementHandler extends DefaultHandler {
private boolean isElementFound = false;
private String value;
public String getValue() {
return value;
}
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (qName.equals("elem")) {
isElementFound = true;
}
}
#Override
public void endElement(String uri, String localName, String qName) {
if (qName.equals("elem")) {
isElementFound = false;
}
}
#Override
public void characters(char ch[], int start, int length) {
if (isElementFound) {
value = new String(ch).substring(start, start + length);
}
}
}
Then, the you parse your xml as follows :
String xml = response.toString();
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
InputSource source = new InputSource(new StringReader(xml));
//-- create handlers
MyAttributeHandler handler = new MyAttributeHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse(source);
System.out.println("value = " + handler.getValue());
More general question about sax parsing.
Here one does not need XML. A two-liner:
String xmlContent = response.toString();
String value = xmlContent.replaceFirst("(?sm)^.*<string[^>]*>([^<]*)<.*$", "$1");
if (value == xmlContent) { // No replace
throw new IllegalStateException("Not found");
}
boolean result = Boolean.valueOf(value.trim().toLowerCase());
With XML one could do:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputSource);
String xml = doc.getDocumentElement().getTextContent();
I have an XML file like this one:
<?xml version="1.0" encoding="UTF-8"?>
<Article>
<ArticleTitle>Java-SAX Tutorial</ArticleTitle>
<Author>
<FamilyName>Yong</FamilyName>
<GivenName>Mook</GivenName>
<GivenName>Kim</GivenName>
<nickname>mkyong</nickname>
<salary>100000</salary>
</Author>
<Author>
<FamilyName>Low</FamilyName>
<GivenName>Yin</GivenName>
<GivenName>Fong</GivenName>
<nickname>fong fong</nickname>
<salary>200000</salary>
</Author>
</Article>
I have tried the example in mkyong's tutorial here and I can retrieve data perfectly from it using SAX, it gives me:
Article Title : Java-SAX Tutorial
Given Name : Kim
Given Name : Mook
Family Name : Yong
Given Name : Yin
Given Name : Fong
Family Name : Low
But I want it to give me something like this:
Article Title : Java-SAX Tutorial
Author : Kim Mook Yong
Author : Yin Fong Low
In other terms, I would like to retrieve some of the child nodes of the node Author, not all of them, put them in a string variable and display them.
This is the class I use in order to parse the Authors with the modification I have tried to do:
public class ReadAuthors {
public void parse(String filePath) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean bFamilyName = false;
boolean bGivenName = false;
#Override
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("FamilyName")) {
bFamilyName = true;
}
if (qName.equalsIgnoreCase("GivenName")) {
bGivenName = true;
}
}
#Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
}
#Override
public void characters(char ch[], int start, int length) throws SAXException {
String fullName = "";
String familyName = "";
String givenName ="";
if (bFamilyName) {
familyName = new String(ch, start, length);
fullName += familyName;
bFamilyName = false;
}
if (bGivenName) {
givenName = new String(ch, start, length);
fullName += " " + givenName;
bGivenName = false;
}
System.out.println("Full Name : " + fullName);
}
};
saxParser.parse(filePath, handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
With this modification, it only gives me the ArticleTitle value and it doesn't return anything regarding the authors full names.
I have another class for parsing the ArticleTitle node and they are both called in a Main class.
What did I do wrong? And how can I fix it?
The fullName variable is overwritten everytime when the characters method is called. I think you should move out that variable into the handler: init with empty string when Author starts and write out when it ends. The concatenation should work as you did. I haven't tried this out but something similear should work:
public class ReadAuthors {
public void parse(String filePath) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean bName = false;
String fullName = "";
#Override
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
if (qName.equalsIgnoreCase("FamilyName")) {
bName = true;
}
if (qName.equalsIgnoreCase("GivenName")) {
bName = true;
}
if (qName.equalsIgnoreCase("Author")) {
fullName = "";
}
}
#Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
if (qName.equalsIgnoreCase("Author")) {
System.out.println("Full Name : " + fullName);
}
}
#Override
public void characters(char ch[], int start, int length) throws SAXException {
String name = "";
if (bName) {
name = new String(ch, start, length);
fullName += name;
bName = false;
}
}
};
saxParser.parse(filePath, handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
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.
I am tryin to get rss feed using xml parsing and
I am getting problem while parsing xml data using SAXParser
I have tried something like
In my MainActivity.java
try{
/****** Creating a new instance of the SAX parser ****************/
SAXParserFactory saxPF = SAXParserFactory.newInstance();
SAXParser saxParser = saxPF.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
URL url = new URL("http://ibnlive.in.com/ibnrss/rss/world/world.xml");
myXMLHandler = new FeedsXMLHandler();
xmlReader.setContentHandler(myXMLHandler);
xmlReader.parse(new InputSource(url.openStream()));
}catch (Exception e) {
e.printStackTrace();
}
I am retriving data from my handler using
ArrayList<FeedsItems> feedsData = myXMLHandler.getXMLData();
Log.v("size",Integer.toString(feedsData.size()));
Here its showing size as zero.
My FeedsXMLHandler.java
private ArrayList<FeedsItems> dataArray = new ArrayList<FeedsItems>();
private FeedsItems data = null;
#Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException
{
elementValue = "";
elementOn = true;
if (localName.equalsIgnoreCase("rss"))
{
// data = new FeedsItems();
}
else if (localName.equalsIgnoreCase("item"))
{
data = new FeedsItems();
Log.v("Item","I am in item block");
}
else if (localName.equalsIgnoreCase("description"))
{
bufferDesc = new StringBuilder();
elementOn = true;
}
else if (localName.equalsIgnoreCase("title"))
{
bufferTitle = new StringBuilder();
elementOn = true;
}
else if(localName.equalsIgnoreCase("link"))
{
bufferLink = new StringBuilder();
elementOn = true;
}
}
/*********** Method will be called when the tags of the XML end **************/
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
elementOn = false;
/*** Sets the values after retrieving the values from the XML tags ******/
if (localName.equalsIgnoreCase("title"))
{
elementOn = false;
data.setTitle(bufferTitle.toString());
bufferTitle.delete(0,bufferTitle.length());
}
else if (localName.equalsIgnoreCase("link")){
elementOn = false;
data.setFeedsUrl(bufferLink.toString());
bufferLink.delete(0,bufferLink.length());
}
else if (localName.equalsIgnoreCase("description")){
elementOn = false;
data.setDescription(bufferDesc.toString());
bufferDesc.delete(0, bufferDesc.length());
}
else if (localName.equalsIgnoreCase("item")){
dataArray.add(data);
}
}
I am not able to understand whats wrong in it. I have already implemented xml parsing using SAXParser in this method. Any help or suggestion will be welcome
I am using the SAX Parser for XML Parsing. The problem is if I print, everything is fine. However, If I want to save anything, I get this error message (with the typos):
"XML Pasing Excpetion = java.lang.NullPointerException"
My code is given below:
Parser code:
try {
/** Handling XML */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
/** Send URL to parse XML Tags */
URL sourceUrl = new URL(
"http://50.19.125.224/Demo/VeryGoodSex_and_the_City_S6E6.xml");
/** Create handler to handle XML Tags ( extends DefaultHandler ) */
MyXMLHandler myXMLHandler = new MyXMLHandler();
xr.setContentHandler((ContentHandler) myXMLHandler);
xr.parse(new InputSource(sourceUrl.openStream()));
} catch (Exception e) {
System.out.println("XML Pasing Excpetion = " + e);
}
Object to hold XML parsed Info:
public class ParserObject {
String name=null;
String description=null;
String bitly=null; //single
String productLink=null;//single
String productPrice=null;//single
Vector<String> price=null;
}
Handler class:
static ParserObject[] xmlDataObject = null;
public void endElement(String uri, String localName, String qName)
throws SAXException {
currentElement = false;
if (qName.equalsIgnoreCase("title"))
{
xmlDataObject[index].name=currentValue;
}
else if (qName.equalsIgnoreCase("artist"))
{
xmlDataObject[index].artist=currentValue;
}
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentElement = true;
if (qName.equalsIgnoreCase("allinfo"))
{
System.out.println("started");
}
else if (qName.equalsIgnoreCase("tags"))
{
insideTag=1;
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentElement) {
currentValue = new String(ch, start, length);
currentElement = false;
}
}
Your ParserObject array i.e xmlDataObject is having null value thats is why it is showing null pointer exception. This is my View and it might be wrong but once check it too.