So I've been doing a lot of looking on both stackoverflow and google in general to try and answer my following question, but I have been unable to find anything that can help me to get this work 100%. I'm pretty sure I have everything except a SMALL error correct, but obviously you guys probably have suggestions anyway, so go for it!
And, here we go: I've been using HTTPClient to test an API on a few different environments, and I got HTTPPost methods to accept JSON payloads but now I'm trying to send payloads using XML and I'm running into some issues. It seems that the XML string that I'm creating (in the code below) is correct... so I'm stumped as to why this isn't working. ALSO: got most of the DOM code from the internet (to build up the XML payload) so feel free to bring that into question as well...
My code is the following:
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element subscription = doc.createElement("subscription");
doc.appendChild(subscription);
subscription.setAttribute("email", "patricia#test.intershop.de");
etc....
etc....
etc....
etc....
DOMSource domSource = new DomSource(doc);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
String XMLpayload = writer.toString();
[name of my HttpRequest].setEntity(new StringEntity(XMLpayload));
[name of my HttpResponse] = client.execute(request);
now... I'm looking to achieve the payload seen BELOW:
<subscription>
<email>patricia#test.intershop.de</email>
<firstName>Patricia</firstName>
<lastName>Miller</lastName>
<title>Ms.</title>
<gender>Female</gender>
</subscription>
When I print out the payload that I am sending currently it looks like the following:
?xml version="1.0" encoding="UTF-8" standalone="no"? subscription email="patricia#test.intershop.de" firstName="Patricia" gender="Female" lastName="Miller" title="Ms."/
(NOTE: I REMOVED THE < AND > BRACKETS. THEY APPEAR WHERE THEY SHOULD!)
But, I'm receiving a 400 error. Any ideas here? I know I have the proper headers, the URL is correct, etc. It's absolutely something with what I'm doing with the payload. Any thoughts would be greatly appreciated!!
Best!
In your expected payload, 'email','firstname',etc.. are child elements of Subscription element. As per the code, they are added as attributes of your 'subscription' element. If you need 'email','firstname',etc.. as child elements, you should use appendChild() instead of setAttribute().
Element email = doc.createElement("email");
email.appendChild(document.createTextNode("patricia#test.intershop.de"));
subscription.appendChild(email);
Related
So I've gotten help from here already so I figured why not try it out again!? Any suggestions would be greatly appreciated.
I'm using HTTP client and making a POST request; the response is an XML body that looks like the following:
<?xml version="1.0" encoding="UTF-8"?>
<CartLink
xmlns="http://api.gsicommerce.com/schema/ews/1.0">
<Name>vSisFfYlAPwAAAE_CPBZ3qYh</Name>
<Uri>carts/vSisFfYlAPwAAAE_CPBZ3qYh</Uri>
</CartLink>
Now...
I have an HttpEntity which is
[HttpResponse].getEntity().
Then I get a String representation of the response (which is XML in this case) by saying
String content = EntityUtils.toString(HttpEntity)
I tried following some of the suggestions on this post: How to create a XML object from String in Java? but it did not seem to work for me. When I built up the document it still appeared to be null.
MY END GOAL here is just to get the NAME field.. i.e. the "vSisFfYlAPwAAAE_CPBZ3qYh" part. So do I want to build up a document and then extract it...? Or is there a simpler way? I've been trying different things and I can't seem to get it to work.
Thanks for all of the help guys, it is most appreciated!!
Instead of trying to extract the value with string manipulation, try to use Java's inbuilt ability to parse XML. That's a much better approach. Http Components returns responses in an XML format - there's a reason for that. :)
Here's probably one way to solve your problem:
// Parse the response using DocumentBuilder so you can get at elements easily
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(response);
Element root = doc.getDocumentElement();
// Now let's say you have not one, but 'n' nodes that contain the value
// you're looking for. Use NodeList to get a list of all those nodes and just
// pull out the tag/attribute's value you want.
NodeList nameNodesList = doc.getElementsByTagName("Name");
ArrayList<String> nameValues = null;
// Now iterate through the Nodelist to get the values you want.
for (int i=0; i<nameNodesList.getLength(); i++){
nameValues.add(nameNodesList.item(i).getTextContent());
}
The ArrayList "nameValues" will now hold every single value contained within "Name" tags. You could also create a HashMap to store a key value pair of Nodes and their respective text contents.
Hope this helps.
First of all, thanks to all the people who's going to spend a little time on this question.
Second, sorry for my english (not my first language! :D).
Well, here is my problem.
I'm learning Android and I'm making an app which uses a XML file to store some info. I have no problem creating the file, but trying to read de XML tags with XPath (DOM, XMLPullParser, etc. only gave me problems) I've been able to read, at least, the first one.
Let's see the code.
Here is the XML file the app generates:
<dispositivo>
<id>111</id>
<nombre>Name</nombre>
<intervalo>300</intervalo>
</dispositivo>
And here is the function which reads the XML file:
private void leerXML() {
try {
XPathFactory factory=XPathFactory.newInstance();
XPath xPath=factory.newXPath();
// Introducimos XML en memoria
File xmlDocument = new File("/data/data/com.example.gps/files/devloc_cfg.xml");
InputSource inputSource = new InputSource(new FileInputStream(xmlDocument));
// Definimos expresiones para encontrar valor.
XPathExpression tag_id = xPath.compile("/dispositivo/id");
String valor_id = tag_id.evaluate(inputSource);
id=valor_id;
XPathExpression tag_nombre = xPath.compile("/dispositivo/nombre");
String valor_nombre = tag_nombre.evaluate(inputSource);
nombre=valor_nombre;
} catch (Exception e) {
e.printStackTrace();
}
}
The app gets correctly the id value and shows it on the screen ("id" and "nombre" variables are assigned to a TextView each one), but the "nombre" is not working.
What should I change? :)
Thanks for all your time and help. This site is quite helpful!
PD: I've been searching for a response on the whole site but didn't found any.
You're using the same input stream twice, but the second time you use it it's already at the end of file. You have to either open the stream once more or buffer it e.g. in a ByteArrayInputStream and reuse it.
In your case doing this:
inputSource = new InputSource(new FileInputStream(xmlDocument));
before this line
XPathExpression tag_nombre = xPath.compile("/dispositivo/nombre");
should help.
Be aware though that you should properly close your streams.
The problem is that you cannot re-use the stream-input-source multiple times - the first call to tag_id.evaluate(inputSource) already has read the input up to the end.
One solution would be to parse Document in advance:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
Document document = documentBuilderFactory.newDocumentBuilder().parse(inputSource);
Source source = new DOMSource(document);
// evalute xpath-expressions on the dom source
I get a SOAP message from a web service, and I can convert the response string to an XML file using the below code. This works fine. But my requirement is not to write the SOAP message to a file. I just need to keep this XML document object in memory, and extract some elements to be used in further processing. However, if I just try to access the document object below, it comes as empty.
Can somebody please tell me how I can convert a String to an in-memory XML object (without having to write to a file)?
String xmlString = new String(data);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
// Use String reader
Document document = builder.parse( new InputSource(
new StringReader( xmlString ) ) );
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource( document );
Result dest = new StreamResult( new File( "xmlFileName.xml" ) );
aTransformer.transform( src, dest );
}
Remove the 5 last lines of code, and you'll just have the DOM document in memory. Store this document in some field, rather than in a local variable.
If that isn't sufficient, then please explain, with code, what you mean with "if I just try to access the document object below, it comes as empty".
JB Nizet is right, the first steps create a DOM out of xmlString. That will load your xmlString (or SOAP message) into an in-memory Document. What the following steps are doing (all the things related with the Transform) is to serialize the DOM to a file (xmlFileName.xml), which is not what you want to do, right?
When you said that your DOM is empty, I think you tried to print out the content of your DOM with document.toString(), and returned something like "[document: null]". This doesn't mean your DOM is empty. Actually your DOM contains data. You need now to use the DOM API to get access to the nodes inside your document. Try something like document.getChildNodes(), document.getElementsByTagName(), etc
I've got an xml file looked like this. employees.xml
<Employees>
<Employee>
<FirstName>myFirstName</FirstName>
<LastName>myLastName</LastName>
<Salary>10000</Salary>
<Employee>
</Employees>
Now how do I add new Employee elements to the existing XML file?.. An example code is highly appreciated.
You can't 'write nodes to an existing XML file.' You can read an existing XML file into memory, add to the data model, and then write a new file. You can rename the old file and write the new file under the old name. But there is no commonly-used Java utility that will modify an XML file in place.
To add to an existing XML file, you generally need to read it in to an internal data structure, add the needed data in the internal form and then write it all out again, overwriting the original file.
The internal structure can be DOM or one of your own making, and there are multiple ways of both reading it in and writing it out.
If the data is reasonably small, DOM is probably easiest, and there is some sample code in the answers to this related question.
If your data is large, DOM will not do. Possible approaches are to use SAX to read and write (though SAX is traditionally only a reading mechanism) as described in an answer to another related question.
You might also want to consider JAXB or (maybe even best) StAX.
Please use xstream to parse your file as an object, or create a list with employees and then you can directly convert that to xml.
I think this link can be useful for you.
Here you have samples how to read / parse, modify (add elements) and save (write to xml file again).
The following samples you can find at: http://www.petefreitag.com/item/445.cfm
Read:
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse("/path/to/file.xml");
Modify:
// attributes
Node earth = doc.getFirstChild();
NamedNodeMap earthAttributes = earth.getAttributes();
Attr galaxy = doc.createAttribute("galaxy");
galaxy.setValue("milky way");
earthAttributes.setNamedItem(galaxy);
// nodes
Node canada = doc.createElement("country");
canada.setTextContent("ca");
earth.appendChild(canada);
Write XML file:
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
You need to use DOM to write/edit your xml file.
It's very easy:
You just need to create nodes and add attributes to it.
You can also write/edit XSLT files by using DOM.
just search google for DOM java
How do I control the order that the XML attributes are listed within the output file?
It seems by default they are getting alphabetized, which the program I'm sending this XML to apparently isn't handling.
e.g. I want zzzz to show first, then bbbbb in the following code.
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element root = doc.createElement("requests");
doc.appendChild(root);
root.appendChild(request);
root.setAttribute("zzzzzz", "My z value");
root.setAttribute("bbbbbbb", "My b value");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(file));
transformer.transform(source, result);
The order of attributes is defined to be insignificant in XML: no conformant XML application should produce results that depend on the order in which attributes appear. Therefore, serializers (code that produces lexical XML as output) will usually give you no control over the order.
Now, it would sometimes be nice to have that control for cosmetic reasons, because XML is designed to be human-readable. So there's a valid reason for wanting the feature. But the fact is, I know of no serializer that offers it.
I had the same issue when I used XML DOM API for writing file. To resolve the problem I had to use XMLStreamWriter. Attributes appear in a xml file in the order you write it using XMLStreamWriter.
XML Canonicalisation results in a consistent attribute ordering, primarily to allow one to check a signature over some or all of the XML, though there are other potential uses. This may suit your purposes.
If you don't want to use another framework just for a custom attribute order you can simply add an order identifier to the attributes.
<someElement a__price="32" b__amount="3"/>
After the XML serializer is done post process the raw XML like so:
public static String removeAttributeOrderIdentifiers(String xml) {
return xml.replaceAll(
" [a-z]__(.+?=\")",
"$1"
);
}
And you will get:
<someElement amount="3" price="32"/>