I need to load an XML files, but there exists two identical formats of the file, save for the namespace being different - in my simplified example,
apple:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="apple">
</ns2:container>
pear:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="pear">
</ns2:container>
The XmlRootElement references a specific namespace, and so I can't process both files the same way:
public class NamespaceTest {
#XmlRootElement(namespace = "apple")
public static class Container {
}
public static void main(final String[] args) throws Exception {
// Correct namespace - works
unmarshall("""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="apple">
</ns2:container>
""");
// Incorrect namespace - doesn't work
unmarshall("""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="pear">
</ns2:container>
""");
}
private static void unmarshall(final String xml) throws Exception {
try (Reader reader = new StringReader(xml)) {
System.out.println(JAXBContext.newInstance(Container.class).createUnmarshaller().unmarshal(reader));
}
}
}
}
Gives the output:
com.my.app.NameSpaceTest$Container#77167fb7
Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"pear", local:"container"). Expected elements are <{apple}container>
At the moment I've got this working in a sub-optimal way by modifying the data as it's being read, using https://stackoverflow.com/a/50800021 - but I'd like to move this into JAXB if possible.
public class NameSpaceTest {
#XmlRootElement(namespace = "apple")
public static class Container {
}
public static void main(final String[] args) throws Exception {
// Correct namespace
unmarshall("""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="apple">
</ns2:container>
""");
// Incorrect namespace
unmarshall("""
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:container xmlns:ns2="pear">
</ns2:container>
""");
}
private static void unmarshall(final String xml) throws Exception {
try (Reader reader = new TranslatingReader(new BufferedReader(new StringReader(xml))) {
#Override
public String translate(final String line) {
return line.replace("pear", "apple");
}
}) {
System.out.println(JAXBContext.newInstance(Container.class).createUnmarshaller().unmarshal(reader));
}
}
/** #see Source */
private abstract static class TranslatingReader extends Reader {
private final BufferedReader input;
private StringReader output = new StringReader("");
public TranslatingReader(final BufferedReader input) {
this.input = input;
}
public abstract String translate(final String line);
#Override
public int read(final char[] cbuf, int off, int len) throws IOException {
int read = 0;
while (len > 0) {
final int nchars = output.read(cbuf, off, len);
if (nchars == -1) {
final String line = input.readLine();
if (line == null) {
break;
} else {
output = new StringReader(translate(line) + System.lineSeparator());
}
} else {
read += nchars;
off += nchars;
len -= nchars;
}
}
if (read == 0) {
read = -1;
}
return read;
}
#Override
public void close() throws IOException {
input.close();
output.close();
}
}
}
Output:
com.my.app.NameSpaceTest$Container#6ce139a4
com.my.app.NameSpaceTest$Container#18ce0030
Assumptions
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>jaxb-test</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.2</version> <!-- latest, depends on jakarta.xml.bind:jakarta.xml.bind-api:3.0.1 -->
</dependency>
</dependencies>
</project>
OOP-Solution
We abstract (public) Container, and introduce (private or the visibility of our choice(, empty)) implementations to it, with correct qName:
public class NamespaceTest {
public static interface Container {
}
#XmlRootElement(namespace = "apple", name = "container")
private static class ContainerApple implements Container {
}
#XmlRootElement(namespace = "pear", name = "container")
private static class ContainerPear implements Container {
}
...
..!
With identical main method, unmarshall would (still) look like:
...
private static void unmarshall(final String xml) throws Exception {
Unmarshaller umler = CTXT.createUnmarshaller();
try ( Reader reader = new StringReader(xml)) {
System.out.println(umler.unmarshal(reader)
);
}
}
private static final JAXBContext CTXT = initContext();
private static JAXBContext initContext() {
try {
return JAXBContext.newInstance(ContainerApple.class, ContainerPear.class);
} catch (JAXBException ex) {
throw new IllegalStateException("Could not initialize jaxb context.");
}
}
}
Singleton JAXBContext.
(static) Initialization with:
catch exception and re-throw (runtime/unchecked).
all (known) jaxb classes/packages/context(configs).
Prints Us:
com.example.jaxb.test.NamespaceTest$ContainerApple#4493d195
com.example.jaxb.test.NamespaceTest$ContainerPear#2781e022
Filtering the data as it's being read is the right approach (JAXB, or data binding in general, isn't an ideal technology choice if you have to handle versions and variants of the vocabulary). But filter it using a SAX filter, not at the stream level.
Alternatively, normalise the data using an XSLT transformation before processing it using JAXB.
One option is to use a custom org.xml.sax.ContentHandler that rewrites the sax events for namespaces before it delegates to the "normal" Content Handler for jaxb.
Here a self contained example:
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class JaxbSaxRewriteNamespaceExample {
#XmlRootElement(name = "container", namespace = "apple")
#XmlAccessorType(XmlAccessType.NONE)
static class Container {
#XmlAttribute(namespace = "apple")
private String attribute;
#XmlElement(namespace = "apple")
private String element;
public String getAttribute() {
return attribute;
}
public String getElement() {
return element;
}
}
public static void main(String[] args) throws Exception {
String orangeXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n"
+ "<ns2:container xmlns:ns2=\"apple\" ns2:attribute=\"oranges\"><ns2:element>Orange Element</ns2:element>\r\n"
+ "</ns2:container>";
String appleXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n"
+ "<ns2:container xmlns:ns2=\"apple\" ns2:attribute=\"apples\"><ns2:element>Apple Element</ns2:element>\r\n"
+ "</ns2:container>";
JAXBContext jc = JAXBContext.newInstance(Container.class);
Container orange = read(jc, orangeXml, Collections.singletonMap("orange", "apple"));
Container apple = read(jc, appleXml, Collections.emptyMap());
System.out.println(orange.getAttribute());
System.out.println(orange.getElement());
System.out.println(apple.getAttribute());
System.out.println(apple.getElement());
}
private static Container read(JAXBContext jc, String xml, Map<String, String> namespaceMapping) throws Exception {
UnmarshallerHandler unmarshallerHandler = jc.createUnmarshaller().getUnmarshallerHandler();
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true); // Make sure sax parser is namespace aware
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
// Wrap the Jaxb ContentHandler with the custome NamespaceRenamer
xr.setContentHandler(new RenameNamespaceContentHandler(unmarshallerHandler, namespaceMapping));
// See javadoc of InputSource for more options to pass in data, e.g. InputStream
InputSource inputSource = new InputSource(new StringReader(xml)); //
xr.parse(inputSource);
return (Container) unmarshallerHandler.getResult();
}
public static class RenameNamespaceContentHandler implements ContentHandler {
private final ContentHandler delegate;
private final Map<String, String> namespaceMapping;
public RenameNamespaceContentHandler(ContentHandler delegate, Map<String, String> namespaceMapping) {
this.delegate = delegate;
this.namespaceMapping = namespaceMapping;
}
#Override
public void setDocumentLocator(Locator locator) {
delegate.setDocumentLocator(locator);
}
#Override
public void startDocument() throws SAXException {
delegate.startDocument();
}
#Override
public void endDocument() throws SAXException {
delegate.endDocument();
}
#Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
if (namespaceMapping.containsKey(uri)) {
delegate.startPrefixMapping(prefix, namespaceMapping.get(uri));
}
delegate.startPrefixMapping(prefix, uri);
}
#Override
public void endPrefixMapping(String prefix) throws SAXException {
delegate.endPrefixMapping(prefix);
}
#Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
delegate.startElement(uri, localName, qName, atts);
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
delegate.endElement(uri, localName, qName);
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
delegate.characters(ch, start, length);
}
#Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
delegate.ignorableWhitespace(ch, start, length);
}
#Override
public void processingInstruction(String target, String data) throws SAXException {
delegate.processingInstruction(target, data);
}
#Override
public void skippedEntity(String name) throws SAXException {
delegate.skippedEntity(name);
}
}
}
Related
i try to add namespaceURI or ignore namespace during unmarshalling XML document for converte in to java object this xmlns attibute on my #XmlRootElement prevent conversion.
I prefer adding the namespace , I tried namespace = "htpp" and also "xmlns="htpp""
Example ignore namespaceURI
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
public class NamespaceFilter extends XMLFilterImpl {
private String usedNamespaceUri;
private boolean addNamespace;
//State variable
private boolean addedNamespace = false;
public NamespaceFilter(String namespaceUri,
boolean addNamespace) {
super();
if (addNamespace)
this.usedNamespaceUri = namespaceUri;
else
this.usedNamespaceUri = "";
this.addNamespace = addNamespace;
}
#Override
public void startDocument() throws SAXException {
super.startDocument();
if (addNamespace) {
startControlledPrefixMapping();
}
}
#Override
public void startElement(String arg0, String arg1, String arg2,
Attributes arg3) throws SAXException {
super.startElement(this.usedNamespaceUri, arg1, arg2, arg3);
}
#Override
public void endElement(String arg0, String arg1, String arg2)
throws SAXException {
super.endElement(this.usedNamespaceUri, arg1, arg2);
}
#Override
public void startPrefixMapping(String prefix, String url)
throws SAXException {
if (addNamespace) {
this.startControlledPrefixMapping();
} else {
//Remove the namespace, i.e. donĀ“t call startPrefixMapping for parent!
}
}
private void startControlledPrefixMapping() throws SAXException {
if (this.addNamespace && !this.addedNamespace) {
//We should add namespace since it is set and has not yet been done.
super.startPrefixMapping("", this.usedNamespaceUri);
//Make sure we dont do it twice
this.addedNamespace = true;
}
}
public static Object unmarshallWithFilter(Unmarshaller unmarshaller,
java.io.File source) throws FileNotFoundException, JAXBException
{
try(FileReader fr = new FileReader(source);) {
XMLReader reader = new NamespaceFilter(null, false);
InputSource is = new InputSource(fr);
SAXSource ss = new SAXSource(reader, is);
return unmarshaller.unmarshal(ss);
} catch (IOException e) {
//not technically a jaxb exception, but close enough
throw new JAXBException(e);
}
}
i Have this error
java.lang.IllegalStateException: Failed to execute CommandLineRunner
...
Caused by: java.lang.NullPointerException: No parent for filter
I also try remove xmlns with FilterInputStream but do no things
I am a bit lost at this point. I am by no means a SOAP/JAXb expert, however, I am trying to create a generic class that will marshal/call/unmarshal for any service. I am using the Weather Service wsdl as a starting point to prove out the concept.
I have finally gotten the marshalling, call and unmarshalling to execute without error, however, the response object is not being populated. Can anyone assist in identifying what I am doing incorrectly? I am also looking for a good explanation to the answer if possible so I can learn from this experience.
Again, there is no error while excuting. The issue is that the value of GetCityWeatherByZIPResponse.GetCityWeatherByZIPResult comes out to be null. I know the document is returning the correct results as the result printout is as follows:
Result printout:
<?xml version="1.0" encoding="UTF-8"?><GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
<GetCityWeatherByZIPResult>
<Success>true</Success>
<ResponseText>City Found</ResponseText>
<State>MO</State>
<City>Saint Charles</City>
<WeatherStationCity>Farmington</WeatherStationCity>
<WeatherID>4</WeatherID>
<Description>Sunny</Description>
<Temperature>79</Temperature>
<RelativeHumidity>47</RelativeHumidity>
<Wind>CALM</Wind>
<Pressure>30.00S</Pressure>
<Visibility/>
<WindChill/>
<Remarks/>
</GetCityWeatherByZIPResult>
</GetCityWeatherByZIPResponse>
Response: GetCityWeatherByZIPResult: null
Test Web Service:
http://wsf.cdyne.com/WeatherWS/Weather.asmx
Initial call (done via JBehave):
#Given("I call the weather soap service")
public void givenICallTheWeatherSoapService() {
GetCityWeatherByZIP weather = new GetCityWeatherByZIP();
weather.setZIP("63304");
try {
new WeatherTools();
WeatherSoap weatherSoap = new WeatherSoap();
GetCityWeatherByZIPResponse response = weatherSoap.getCityWeatherByZip("63304");
System.out.println("Response: " + response);
} catch (JAXBException | ParserConfigurationException | SOAPException | IOException e) {
Assert.fail(e.getMessage());
}
}
Soap Service Class:
public class WeatherSoap extends PTFSoapClient {
public WeatherSoap() throws JAXBException, ParserConfigurationException, SOAPException {
super(PTFApplication.getConfig(Environment.executionEnv.getEnv(), "Weather SOAP endpoint"));
}
public GetCityWeatherByZIPResponse getCityWeatherByZip(String zip) throws JAXBException, SOAPException, IOException {
GetCityWeatherByZIP weatherByZip = new GetCityWeatherByZIP();
weatherByZip.setZIP(zip);
try {
sendRequest(weatherByZip);
return (GetCityWeatherByZIPResponse) unmarshallResponse(GetCityWeatherByZIPResponse.class);
} catch (ParserConfigurationException | XMLStreamException e) {
e.printStackTrace();
return null;
}
}
}
Base Framework Class genericizing the call (usable for all SOAP calls):
public class PTFSoapClient {
private JAXBContext context;
private Marshaller marshaller;
private Object object;
private SOAPMessage message;
private String endpoint;
private SOAPMessage response;
public PTFSoapClient(String endpoint) {
this.endpoint = endpoint;
}
public void toConsole() throws JAXBException, SOAPException, IOException {
message.writeTo(System.out);
System.out.print("\n");
}
public SOAPMessage sendRequest(Object obj) throws JAXBException, ParserConfigurationException, SOAPException {
object = obj;
context = JAXBContext.newInstance(obj.getClass());
marshaller = context.createMarshaller();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().newDocument();
marshaller.marshal(object,doc);
MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();
message.getSOAPBody().addDocument(doc);
message.saveChanges();
SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
response = connection.call(message, endpoint);
connection.close();
try {
System.out.println("Response:");
response.writeTo(System.out);
System.out.println("");
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
public Object unmarshallResponse(Class<?> classname) throws JAXBException, XMLStreamException, SOAPException, IOException {
Document doc = response.getSOAPBody().extractContentAsDocument();
try {
System.out.println("Document: ");
printDocument(doc, System.out);
System.out.println("");
} catch (TransformerException e) {
e.printStackTrace();
}
Unmarshaller unmarshaller = JAXBContext.newInstance(classname).createUnmarshaller();
return unmarshaller.unmarshal(doc);
}
public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(doc),
new StreamResult(new OutputStreamWriter(out, "UTF-8")));
}
}
Base unmarshal object:
#XmlRootElement(name = "GetCityWeatherByZIPResponse",
namespace = "http://ws.cdyne.com/WeatherWS/")
public class GetCityWeatherByZIPResponse {
GetCityWeatherByZIPResult GetCityWeatherByZIPResult;
public GetCityWeatherByZIPResult getGetCityWeatherByZIPResult() {
return GetCityWeatherByZIPResult;
}
public void setGetCityWeatherByZIPResult(GetCityWeatherByZIPResult GetCityWeatherByZIPResult) {
this.GetCityWeatherByZIPResult = GetCityWeatherByZIPResult;
}
#Override
public String toString() {
return "GetCityWeatherByZIPResult: " + GetCityWeatherByZIPResult;
}
}
Sub umarshal object:
public class GetCityWeatherByZIPResult {
boolean Success;
String ResponseText;
String State;
String City;
String WeatherStationCity;
String WeatherID;
String Description;
int Temperature;
int RelativeHumidity;
String Wind;
String Pressure;
String Visibility;
String WindChill;
String Remarks;
public boolean isSuccess() {
return Success;
}
public void setSuccess(boolean success) {
Success = success;
}
public String getResponseText() {
return ResponseText;
}
public void setResponseText(String responseText) {
ResponseText = responseText;
}
public String getState() {
return State;
}
public void setState(String state) {
State = state;
}
public String getCity() {
return City;
}
public void setCity(String city) {
City = city;
}
public String getWeatherStationCity() {
return WeatherStationCity;
}
public void setWeatherStationCity(String weatherStationCity) {
WeatherStationCity = weatherStationCity;
}
public String getWeatherID() {
return WeatherID;
}
public void setWeatherID(String weatherID) {
WeatherID = weatherID;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public int getTemperature() {
return Temperature;
}
public void setTemperature(int temperature) {
Temperature = temperature;
}
public int getRelativeHumidity() {
return RelativeHumidity;
}
public void setRelativeHumidity(int relativeHumidity) {
RelativeHumidity = relativeHumidity;
}
public String getWind() {
return Wind;
}
public void setWind(String wind) {
Wind = wind;
}
public String getPressure() {
return Pressure;
}
public void setPressure(String pressure) {
Pressure = pressure;
}
public String getVisibility() {
return Visibility;
}
public void setVisibility(String visibility) {
Visibility = visibility;
}
public String getWindChill() {
return WindChill;
}
public void setWindChill(String windChill) {
WindChill = windChill;
}
public String getRemarks() {
return Remarks;
}
public void setRemarks(String remarks) {
Remarks = remarks;
}
}
Your Current Mapping
When you specify the namespace property on the #XmlRootElement annotation, it only applies to that one element.
#XmlRootElement(name = "GetCityWeatherByZIPResponse",
namespace = "http://ws.cdyne.com/WeatherWS/")
public class GetCityWeatherByZIPResponse {
Your XML Document
Your XML document specifies a default namespace. This means that all elements without another explicit namespace mapping are also part of the http://ws.cdyne.com/WeatherWS/ namespace.
<?xml version="1.0" encoding="UTF-8"?><GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
<GetCityWeatherByZIPResult>
<Success>true</Success>
The Namespace Fix
You are going to want to specify the namespace mapping at the package level so that it applies to all your element mappings. This is done using the package level #XmlSchema annotation on a speciial class called package-info.
#XmlSchema(
namespace = "http://ws.cdyne.com/WeatherWS/",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
I have written more about JAXB and namespace qualification on my blog:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Update
Default Element Names
The default elements for your properties don't match your XML. for the property below the expected element name will be getCityWeatherByZIPResult so you will need to override the default using the #XmlElement annotation.
#XmlElement(name="GetCityWeatherByZIPResult")
public GetCityWeatherByZIPResult getGetCityWeatherByZIPResult() {
return GetCityWeatherByZIPResult;
}
Debugging Tip
When you encounter problems unmarshalling, populate your object model and marshal it to see what the expected XML is based on your current mappings.
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;
I'm running a small Android project which could read RSS/Atom Feed documents, using SAX library. Everything works well for default RSS sources, but with minimized sources (without spaces or new line tokens), it produces nothing but a list of blank items. My logs in Log cat also display nothing. I double check this problems with variant RSS sites, but problems still there. Below is my inheritance class of DefaultHandler which I use to handle Rss sources
public class RssContentHandler extends DefaultHandler {
private static final int UNKNOWN_STATE = -1;
private static final int ELEMENT_START = 0;
private static final int TITLE_END = 1;
private static final int DESCRIPTION_END = 2;
private static final int LINK_END = 3;
private static final int PUBDATE_END = 4;
private static final int CHANNEL_END = 5;
private int iState = UNKNOWN_STATE;
private String fullCharacters;
private boolean itemFound = false;
private RssItem rssItem;
private RssFeed rssFeed;
public RssContentHandler() {
}
public RssFeed getFeed() {
return this.rssFeed;
}
#Override
public void startDocument() {
rssItem = new RssItem();
rssFeed = new RssFeed();
Log.i("startDocument", "startDocument");
}
#Override
public void endDocument() {
}
#Override
public void startElement(String _uri, String _localName, String _qName, Attributes _attributes) {
if (_localName.equalsIgnoreCase("item")) {
itemFound = true;
rssItem = new RssItem();
this.iState = UNKNOWN_STATE;
} else
this.iState = ELEMENT_START;
fullCharacters = "";
}
#Override
public void endElement(String _uri, String _localName, String _qName) {
if (_localName.equalsIgnoreCase("item"))
this.rssFeed.addItem(this.rssItem);
else if (_localName.equalsIgnoreCase("title"))
this.iState = TITLE_END;
else if (_localName.equalsIgnoreCase("description"))
this.iState = DESCRIPTION_END;
else if (_localName.equalsIgnoreCase("link"))
this.iState = LINK_END;
else if (_localName.equalsIgnoreCase("pubDate"))
this.iState = PUBDATE_END;
else if (_localName.equalsIgnoreCase("channel"))
this.iState = CHANNEL_END;
else
this.iState = UNKNOWN_STATE;
}
#Override
public void characters(char[] _ch, int _start, int _length) {
String strCharacters = new String(_ch, _start, _length);
if (this.iState == ELEMENT_START)
fullCharacters += strCharacters;
else {
if (!itemFound) {
switch (this.iState) {
case TITLE_END:
this.rssFeed.setTitle(fullCharacters);
break;
case DESCRIPTION_END:
this.rssFeed.setDescription(fullCharacters);
break;
case LINK_END:
this.rssFeed.setLink(fullCharacters);
break;
case PUBDATE_END:
this.rssFeed.setPubDate(fullCharacters);
break;
}
} else {
switch (this.iState) {
case TITLE_END:
this.rssItem.setTitle(fullCharacters);
Log.i("characters", fullCharacters);
break;
case DESCRIPTION_END:
this.rssItem.setDescription(fullCharacters);
break;
case LINK_END:
this.rssItem.setLink(fullCharacters);
break;
case PUBDATE_END:
this.rssItem.setPubDate(fullCharacters);
break;
}
}
this.iState = UNKNOWN_STATE;
}
}
}
and snippet to setup the parser:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
try {
request.setURI(new URI(_strUrl));
} catch (URISyntaxException e) {
e.printStackTrace();
}
HttpResponse response = client.execute(request);
Reader inputStream = new InputStreamReader(response.getEntity().getContent());
RssContentHandler rssContentHandler = new RssContentHandler();
InputSource inputSource = new InputSource();
inputSource.setCharacterStream(inputStream);
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
saxParser.parse(inputSource, rssContentHandler);
this.rssFeed = rssContentHandler.getFeed();
P/s: i'm using Android 2.3 x86 installed on VirtualBox for Debugging, and these sources work fine with the built-in RSS Reader app come with the x86 version. So what's wrong here?
Try with _qName instead of _localName.
Your xml contains CDATA so You cann't parse the XML response with your current parser. You have to use LexicalHandler for parsing Raw HTML.
public class MyHandler implements LexicalHandler {
public void startDTD(String name, String publicId, String systemId)
throws SAXException {}
public void endDTD() throws SAXException {}
public void startEntity(String name) throws SAXException {}
public void endEntity(String name) throws SAXException {}
public void startCDATA() throws SAXException {}
public void endCDATA() throws SAXException {}
public void comment (char[] text, int start, int length)
throws SAXException {
String comment = new String(text, start, length);
System.out.println(comment);
}
You can also parse your XML with DOM if memory is not the issue. For more help visit Handling Lexical Events
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.