I am using xmlstreamreader in java to read attribute values and other data. This is the xml String:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><samlp:AuthnReques
t xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL
="http://localhost:8080/consumer.jsp" **ID="abc"** **IssueInstant="2012-04-14T11:44:49
:796"** ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="
2.0">**<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://loca
lhost:8080/saml/SProvider.jsp</saml:Issuer>**<Signature xmlns="http://www.w3.org/2
000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.or
g/2001/10/xml-exc-c14n#WithComments"/><SignatureMethod Algorithm="http://www.w3.
org/2000/09/xmldsig#rsa-sha1"/><Reference URI=""><Transforms><Transform Algorith
m="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/></Transforms><DigestM
ethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>VzKYOu1g
ert3DDrNUSO1/Au3PGeD1PEyPuJeI2GO6ec=</DigestValue></Reference></SignedInfo><Sign
atureValue>k7hVlbsEhGW5ryelSbrwWWyJq3cdyDuVeQCOqRilbky8hEk/1sHI9DNOvOlPZ7OC9bI4d
EHm46R1
CDXoXkyOoXdq+3M/HbUakHM7eNvF5+j+NUXUX9dijb/rDzq05VNHcSIDXRpvMc1IRBremi0voVqX
ZuHRn+IBeD8hSK1LXsE=</SignatureValue></Signature></samlp:AuthnRequest>
Then I tried to read the attribute ID, IssueInstant and the element Issuer. all the 3 are highlighted(actually between **) in the above string. I have used the following code:
while(reader.hasNext()){
reader.next();
if(reader.getEventType() == XMLStreamReader.START_ELEMENT){
if(reader.getLocalName().equals("AuthnRequest"))
{
String ns=reader.getNamespaceURI();
System.out.println(ns);
id=reader.getAttributeValue(ns,"ID");
rec_instant=reader.getAttributeValue(ns,"IssueInstant");
System.out.println("1"+id);
System.out.println("2"+rec_instant);
}
else if(reader.getLocalName().equals("Issuer"))
{
rec_issuer=reader.getElementText();
System.out.println("4"+reader.getElementText());
}
}
}
But I am getting the folowing output:
1null
2null
javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,436]
Message: parser must be on START_ELEMENT to read next text
What is the issue?
You are using ns for the attributes, but the attributes are in fact in the null ns (they have no namespace). As for the exception, you are calling getElementText twice. This method is not a pure getter, it also advances the reader to the end element (as per its Javadoc).
As Marko suggests, the exception is due to calling getElementText() twice in a row.
If I change this:
String rec_issuer=reader.getElementText();
System.out.println("4"+reader.getElementText());
to this:
String rec_issuer = reader.getElementText();
System.out.println("4" + rec_issuer);
then I get the following output:
urn:oasis:names:tc:SAML:2.0:protocol
1null
2null
4http://localhost:8080/saml/SProvider.jsp
If I also change the getAttributeValue calls to use null instead of ns, like this:
String id = reader.getAttributeValue(null,"ID");
String rec_instant = reader.getAttributeValue(null,"IssueInstant");
I get:
urn:oasis:names:tc:SAML:2.0:protocol
1abc
22012-04-14T11:44:49:796
4http://localhost:8080/saml/SProvider.jsp
That's using your original XML.
Related
I have an xml file from which i read using an XMLStreamReader object.
So i'll keep it simple :
Let's take this xml example :
<mySample xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attribute1="value1"/>
So what i need is to get the value (as a String) "xmlns:xsi" and get the value (as a String also) "http://www.w3.org/2001/XMLSchema-instance"
I did try to have a test like this :
if (reader.getEventType() != XMLStreamConstants.NAMESPACE){
attributeName = reader.getAttributeLocalName(i);
attributeValue = reader.getAttributeValue(i);
}
else{
attributeName = reader.getNamespacePrefix(i) + reader.getNamespaceURI(i);
attributeValue = reader.getAttributeValue(i);
}
But it did not work.
Obviously i missed something being a newbie to this API, so any help would be very welcome.
The JSR-173 specification (Stax API for Java) states the following regarding the NAMESPACE event :
Namespace
Namespace declarations can also exist outside of a StartElement and may be reported as a
standalone information item. In general Namespaces are reported as part of a StartElement
event. When namespaces are the result of an XQuery or XPath expression they may be
reported as standalone events.
So if you are looking at namespace events, you should most probably be checking StartElement events, and inspect them. Once again, from the spec :
Namespaces can be accessed using the following methods:
int getNamespaceCount();
String getNamespacePrefix(int index);
String getNamespaceURI(int index);
Only the namespaces declared on the current StartElement are available. The list does
not contain previously declared namespaces and does not remove redeclared namespaces.
At any point during the parsing, you can get the current complete namespace context :
The namespace context of the current state is available by calling
XMLStreamReader.getNamespaceContext() or
StartElement.getNamespaceContext(). These methods return an instance of the
javax.xml.namespace.NamespaceContext interface.
That's theory : most namespace declarations come from START_ELEMENT, some may come independently.
In practice, I have never came accross a NAMESPACE event reported by the API when reading from a file. It's almost always reported as part of a START_ELEMENT (and repeated in the corresponding END_ELEMENT), so you must check START_ELEMENT if you are interested in namespace declaration. For example, starting with your document :
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><mySample xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" attribute1=\"value1\"/>";
XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader(new StringReader(xml));
while (reader.hasNext()) {
int event = reader.next();
if (XMLStreamConstants.START_ELEMENT == event) {
if (reader.getNamespaceCount() > 0) {
// This happens
System.out.println("ELEMENT START: " + reader.getLocalName() + " , namespace count is: " + reader.getNamespaceCount());
for (int nsIndex = 0; nsIndex < reader.getNamespaceCount(); nsIndex++) {
String nsPrefix = reader.getNamespacePrefix(nsIndex);
String nsId = reader.getNamespaceURI(nsIndex);
System.out.println("\tNamepsace prefix: " + nsPrefix + " associated with URI " + nsId);
}
}
} else if(XMLStreamConstants.NAMESPACE == event) {
// This almost never happens
System.out.println("NAMESPACE EVENT");
}
}
Will produce :
ELEMENT START: mySample , namespace count is: 1
Namepsace prefix: xsi associated with URI http://www.w3.org/2001/XMLSchema-instance
Bottom line : you should check for NAMESPACE and START_ELEMENT events, even if most of times, you will only have START_ELEMENT reporting namespace declartions, it is not one or the other, it's both.
I am doing JSON parsing in Android by the following steps:
Get an XML response from a web-service using HttpPost object.
Convert this XML to JSON string then JSON object.
Now the problem is that sometimes the XML response has null string or Null tag.
For Example:
<data>
<name>Martin Clark</name>
<city>London</city>
<country>XYZ</country> or <country /> <!-- Sometimes it will blank string like this if country is not available -->
<age>27</age>
</data>
Parsing style:
jsonObject.getString("country"); // It is working perfect when xml is this : <country>XYZ<country/>
jsonObject.getString("country"); // It is giving Exception key is not found when xml is this : <country />
i don't understand why the parser is not giving me BLANK string for blank XML object.
By deep level debugging i have found that XML to JSON converter not produce object corresponding to blank xml object.
Please help me.
Use optString instead, catching the Exception is costly and unnecessary.
public String optString (String name)
Added in API level 1 Returns the value mapped by name if it exists,
coercing it if necessary. Returns the empty string if no such mapping
exists.
public String optString (String name, String fallback)
Added in API level 1 Returns the value mapped by name if it exists,
coercing it if necessary. Returns fallback if no such mapping exists.
Documentation
You can use ths logical solution for your problem.
Try this once.
public static String getStringFromJSON(JSONObject json, String key){
String value = ""; // Blank string by default.
try {
String value = json.getString(key);
return value;
}
catch(JSONException exp){
exp.getMessage();
}
return value; // this wil return BLANk string if object is not prasent.
}
You can you this method for getting String from json object,
I'm trying to pull values from a preset xml file and I keep getting null when I try to check what the value was.
if (pulled.equals("preset")) {
presetName = xmlParser.getAttributeValue(null,"name");
Log.d(TAG, presetName + " = " + xmlParser.getText());
}
This is the xml im Pulling the value from
<?xml version="1.0" encoding="utf-8"?>
<sports>
<sport name="Baseball" paid="false">
<preset name="Pitching Mound">726.0</preset>
<preset name="Base Distance">1080.0</preset>
</sport>
<sport name="Basketball" paid="false">
<preset name="NBA Free Throw Line">181.08</preset>
<preset name="NBA 3pt Line">265.8</preset>
</sport>
<sport name="Cricket" paid="true">
<preset name="Cricket Pitch">2012.0</preset>
<preset name="Testing">0.8</preset>
</sport>
</sports>
Am I doing something wrong?
On XmlPullParser api, the getText() method has the following description:
Returns the text content of the current event as String. The value
returned depends on current event type, for example for
TEXT event it is element content (this is typical case when next()
is used). See description of nextToken() for detailed description of
possible returned values for different types of events.
NOTE: in case of ENTITY_REF, this method returns the entity
replacement text (or null if not available). This is the only case
where getText() and getTextCharacters() return different values.
So based on this description, first you have to check if the current xml node is TEXT in order that getText() doesn't return null.
if (pulled.equals("preset")) {
presetName = xmlParser.getAttributeValue(null,"name");
if (xmlParser.getEventType() == XmlPullParser.TEXT) {
Log.d(TAG, presetName + " = " + xmlParser.getText());
}
}
Hope this helps,
I'm parsing a xml string with dom4j and I'm using xpath to select some element from it, the code is :
String test = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><epp xmlns=\"urn:ietf:params:xml:ns:epp-1.0\"><response><result code=\"1000\"><msg lang=\"en-US\">Command completed successfully</msg></result><trID><clTRID>87285586-99412370</clTRID><svTRID>52639BB8-1-ARNES</svTRID></trID></response></epp>";
SAXReader reader = new SAXReader();
reader.setIncludeExternalDTDDeclarations(false);
reader.setIncludeInternalDTDDeclarations(false);
reader.setValidation(false);
Document xmlDoc;
try {
xmlDoc = reader.read(new StringReader(test));
xmlDoc.getRootElement();
Node nodeStatus = xmlDoc.selectSingleNode("//epp/response/result");
System.out.print(nodeStatus.getText());
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I always get null for the nodeStatus variable. I actualy nead to read the code from the result noad from the xml
<result code="1000">
This is the XML that I am reading from the String test:
<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg lang="en-US">Command completed successfully</msg>
</result>
<trID>
<clTRID>87285586-99412370</clTRID>
<svTRID>52639BB8-1-ARNES</svTRID>
</trID>
</response>
</epp>
Any hints?
Your XML has a namespace. DOM4J returns null because it won't find your nodes.
To make it work, you first have to register the namespaces you are using. You will need a prefix. Any one. And you will have to use that prefix in your XPath.
You could use tns for "target namespace". Then you have to create a xpath object with it like this:
XPath xpath = new DefaultXPath("/tns:epp/tns:response/tns:result");
To register the namespaces you will need to create a Map, add the namespace with the prefix you used in the xpath expression, and pass it to the setNamespaceURIs() method.
namespaces.put("tns", "urn:ietf:params:xml:ns:epp-1.0");
xpath.setNamespaceURIs(namespaces);
Now you can call selectSingleNode, but you will call it on your XPath object passing the document as the argument:
Node nodeStatus = xpath.selectSingleNode(xmlDoc);
From there you can extract the data you need. getText() won't give you the data you want. If you want the contents of the result node as XML, you can use:
nodeStatus.asXML()
Edit: to retrieve just the code, change your XPath to:
/tns:epp/tns:response/tns:result/#code
And retrieve the result with
nodeStatus.getText();
I replaced the double slash // (which means descendant-or-self) with / since the expression contains the full path and / is more efficient. But if you only have one result node in your whole file, you can use:
//result/#code
to extract the data. It will match all descendants. If there is more than one result, it will return a node-set.
I'm using jpachube and am running into problems with .POST on creatDatastream. I am getting POST error 400, and the following details from COSM's debug tool:
{"title":"JSON Parser Error","errors":"lexical error: invalid char in json text. <? xmlversion=\"1.0\"encoding=\"U"}
My XML request body from the COSM debug tool is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<eeml xmlns="http://www.eeml.org/xsd/005"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"><environment><data id="0">
<tag>CPU</tag>
<current_value>0.0</current_value>
</data>
</environment>
</eeml>
COSM's API documentation for what the xml request body should look like is as follows:
<eeml xmlns="http://www.eeml.org/xsd/0.5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" version="0.5.1" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd">
<environment>
<data id="23">
<tag>apple</tag>
<tag>jag</tag>
<tag>tag</tag>
<tag>lag</tag>
<current_value>11</current_value>
<max_value>211.0</max_value>
<min_value>7.0</min_value>
<unit type="conversionBasedUnits" symbol="symbol">label</unit>
</data>
</environment>
The only difference I found was the version #, but I made that switch in the code already and got the same error.
I thought for the v2 of the COSM API was set up so xml and JSON are interchangeable but it converts everything to JSON.
The error is coming from this method call in Pachube.java
public boolean createDatastream(int feed, String s) throws PachubeException {
HttpRequest hr = new HttpRequest("http://api.cosm.com/v2/feeds/"
+ feed + "/datastreams/");
hr.setMethod(HttpMethod.POST);
hr.addHeaderItem("X-PachubeApiKey", this.API_KEY);
hr.setBody(s);
HttpResponse g = this.client.send(hr);
if (g.getHeaderItem("Status").equals("HTTP/1.1 201 Created")) {
return true;
} else {
throw new PachubeException(g.getHeaderItem("Status"));
}
}
Any input appreciated.
Day two...
Modified the createDatastream method using input from bjpirt (much thanks). Method looks like this
public boolean createDatastream(int feed, String s) throws PachubeException {
HttpRequest hr = new HttpRequest("http://api.cosm.com/v2/feeds/"
+ feed + "/datastreams.xml");
hr.setMethod(HttpMethod.POST);
hr.addHeaderItem("X-PachubeApiKey", this.API_KEY);
hr.addHeaderItem("Content-Type:", "application/xml");
hr.setBody(s);
HttpResponse g = this.client.send(hr);
if (g.getHeaderItem("Status").equals("HTTP/1.1 201 Created")) {
return true;
} else {
Log.d("create data stream", "prob");
throw new PachubeException(g.getHeaderItem("Status"));
}
}
This throws the following error for .POST on the COSM debug tool (error code 422):
<?xml version="1.0" encoding="UTF-8"?><errors><title>Unprocessable Entity</title> <error>Stream ID has already been taken</error></errors>
So, naturally, I need to get a title on this request. That is done through the toXMLWithWrapper in Data.java
public String toXMLWithWrapper() {
String ret = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<eeml xmlns=\"http://www.eeml.org/xsd/005\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"5\" xsi:schemaLocation=\"http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd\"><environment>";
ret = ret + ">\n\t<title>" + "cosm app" + "</title>\n\t";//inserted this line to add title
ret = ret + this.toXML() + "</environment></eeml>";
return ret;
}
And the request body looks like (from COSM debug tool):
<?xml version="1.0" encoding="UTF-8"?>
<eeml xmlns="http://www.eeml.org/xsd/005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"><environment>
<title>cosm app</title>
<data id="0">
<tag>CPU</tag>
<current_value >0.0</current_value>
</data></environment></eeml>
This comes back as error code 500 (ouch!)
Response body is
<?xml version="1.0" encoding="UTF-8"?><errors><title>Oops, something's broken</title> <error>We've been unable to complete your request due to a problem with our server</error></errors>
day three
it was pointed out that there was a problem with the xml (see below). I fixed the typo and I'm back to a 422 error. So, looking more closely at the response body I thought maybe that there was something wrong with the data stream. I delete all of the datastreams in the feed, create a new feed, and I get exactly ONE AWESOME HTTP:/1.1 201 - happy, right? Wrong, after the first .POST I get nothing. When I turn the app off and then back on, I'm back to 422 error and the same response body "Stream ID has already been taken". Yikes!
It seems like the xml may be invalid.
The opening <environment> node seems to be closed twice <environment>>
The 422 is probably because you are trying to POST to an existing feed.
To update a feed you need to send a PUT request.
See the Updating a feed docs
The clue is that the system looks like it's expecting json but you're feeding it XML. The default for the v2 api is json, so you'll need to make sure that you're including XML in the URL, e.g:
https://api.cosm.com/v2/feeds/113/datastreams.json
Alternatively, you can set a content type header on the request to indicate this:
Content-Type: application/xml