Jdom2 Sharepoint XML Fields - java

Having some trouble returning certain fields from a SharePoint List SOAP request.
Here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:soap1="http://schemas.microsoft.com/sharepoint/soap/">
<soap:Header/>
<soap:Body>
<soap1:UpdateListItems>
<soap1:listName>69A3FFFA-782B-45D5-B776-2BE6D5645745</soap1:listName>
<soap1:updates>
<Batch OnError="Continue">
<Method ID="1" Cmd="New">
<Field Name="Title">New Item</Field>
</Method>
</Batch>
</soap1:updates>
</soap1:UpdateListItems>
</soap:Body>
</soap:Envelope>
I am able to use the following Jdom2 code to grab certain values like this:
// set your name spaces.
Namespace soap = Namespace.getNamespace("soap","http://www.w3.org/2003/05/soap-envelope");
Namespace soap1 = Namespace.getNamespace("soap1","http://schemas.microsoft.com/sharepoint/soap/");
// drill down into elements
Element rootNode = doc.getRootElement();
// Get Body node
Element body = rootNode.getChild("Body",soap);
// Get UpdateListItem Element
Element UpdateListItems = body.getChild("UpdateListItems",soap1);
// Get updates node
Element updates = UpdateListItems.getChild("updates",soap1);
// Set list name as String variable
String listNameString = UpdateListItems.getChild("listName",soap1).getText();
// Print list text value ** THIS WORKS**
System.out.println(listNameString);
However, I can't seem to figure out how to select the Field elements.
For example: How would I select the "Title" Field?
<Field Name="Title">New Item</Field>
UPDATE:
I also able to get the attribute "Name" from the "Field" element, but can only return or set the name of value of the attribute. I need to be able to access the test within the "Field" Element.
I can get the value of the attribute like this:
System.out.println(field.getAttribute("Name").getValue()); // Prints Title
And I can get the name like this:
System.out.println(field.getAttribute("Name").getName()); // Prints Name
But, I need to be able to return the text value of the element.
UPDATE 2:
I didn't mention. The XML really looks like this:
` <?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:soap1="http://schemas.microsoft.com/sharepoint/soap/">
<soap:Header/>
<soap:Body>
<soap1:UpdateListItems>
<soap1:listName>69A3FFFA-782B-45D5-B776-2BE6D5645745</soap1:listName>
<soap1:updates>
<Batch OnError="Continue">
<Method ID="1" Cmd="New">
<Field Name="Title">New Item</Field>
<Field Name="Classification" Type="Choice">Funny</Field>
<Field Name="Title">New Item</Field>
<Field Name="Title" Type="Text">Funny List Item</Field>
</Method>
</Batch>
</soap1:updates>
</soap1:UpdateListItems>
</soap:Body>
</soap:Envelope>`
I can submit this via SoapUI to SharePoint and it works. But if there are multiple "Field" elements, with different attributes, how can I select the correct one via Jdom2?
I can do this:
String title = field.getText(); //returns New Item
But how would I be able to grab the text from other "Field" elements that use the "Name" attribute?

It is all in the namespaces. You have three of them, soap, soap1, and there's also the default namespace, which, in this case, is "". JDOM designates this namespace as Namespace.NO_NAMESPACE.
So, to get the Field Element from the updates Element, you can do:
Element methods = updates.getChild("Method", Namespace.NO_NAMESPACE);
Element field = methods.getChild("Field", Namespace.NO_NAMESPACE);
These can be made simpler, if you want, by using the getChild method that does not have the namespace parameter at all, like:
Element methods = updates.getChild("Method");
Element field = methods.getChild("Field");
The important thing to see here, is that your document has 3 namespaces, and that the Field element (and Method too) are not in the soap, or soap1 namespace.

Thanks for the help rolfl. I figured it out. You can loop through the Child elements to access the different "Field" attributes. I then test for the attribute name to get or set its content. This is the best I could come up with.
for (Element node : method.getChildren("Field")){
if(node.getAttributeValue("Name").equalsIgnoreCase("Title")){
node.setText("String");
}
System.out.println(node.getAttribute("Name").getValue());
}

Related

How get attribute content by another attribute value with XPath?

I have XML like:
<?xml version='1.0' encoding='UTF-8'?>
<ClinicalDocument xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='urn:hl7-org:v3'
xmlns:ext='urn:hl7-RU-EHR:v1'
xsi:schemaLocation='urn:hl7-org:v3'>
<author>
<time value='20160809000000+0300'/>
<assignedAuthor>
<id root='1.2.643.5.1.13.3.25.1.1.100.1.1.70' extension='1'/>
<id root='1.2.643.100.3' extension='03480134121'/>
<id nullFlavor='NI'/>
</assignedAuthor>
</author>
</ClinicalDocument>
I have to get extension in id with root's value = 1.2.643.100.3.
I must use XPath 2.0.
I have tried:
*[name()='ClinicalDocument']/*[name()='author']/*[name()='assignedAuthor']/*[name()='id' and #id='1.2.643.100.3']/#extension. Not working
/*[name()='ClinicalDocument']/*[name()='author']/*[name()='assignedAuthor']/*[name()='id'][2]/#extension, but order of ids can
mixed. So that, I should retrieve by id's value
It's needed to me for retrieving value by Java's XPathExpression
First, bind namespace prefix, u: to urn:hl7-org:v3.
Then, this XPath,
//u:id[#root='1.2.643.100.3']/#extension
will return 03480134121, as requested.
If you are unable to bind a namespace prefix, you can instead use this XPath,
//*[local-name() ='id' and #root='1.2.643.100.3']/#extension
which will also return 03480134121, as requested.
Correct XPath: /*[name()='ClinicalDocument']/*[name()='author']/*[name()='assignedAuthor']/*[local-name()='id' and #root='1.2.643.100.3']/#extension

Check if element node contains no text using java and Xpath?

I am new to Xpath. I am facing a problem that I have to get a boolean response from Xpath, if an element does not contains any text then it should return false otherwise true. I have seen many examples and I don't have much time to learn Xpath expressions. Below is the Xml file.
<?xml version="1.0" encoding="UTF-8" ?>
<order id="1234" date="05/06/2013">
<customer first_name="James" last_name="Rorrison">
<email>j.rorri#me.com</email>
<phoneNumber>+44 1234 1234</phoneNumber>
</customer>
<content>
<order_line item="H2G2" quantity="1">
<unit_price>23.5</unit_price>
</order_line>
<order_line item="Harry Potter" quantity="2">
<unit_price></unit_price>//**I want false here**
</order_line>
</content>
<credit_card number="1357" expiry_date="10/13" control_number="234" type="Visa" />
</order>
Could you point me the right direction to create xpath expression for this problem.
What I want is a expression(dummy expression) as below.
/order/content/order_line/unit_price[at this point I want to put a validation which will return true or false based on some check of isNull or notNull].
The following xpath will do this:
not(boolean(//*[not(text() or *)]))
but this xpath will also include the credit_card node since it to does not contain any text (the attributes are not text()).
if you also want to exclude node with attributes then use this..
not(boolean(//*[not(text() or * or #*)]))
Following your edit, you can do this..
/order/content/order_line/unit_price[not(text()]
It will return a list of nodes with no text and from there you can test against the count of nodes for your test.
or to return true/false..
not(boolean(/order/content/order_line/unit_price[not(text()]))

How to create XML with declared namespace?

I am creating a xml request using java.
I am new in creating xmls using java.
Here is code:
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("UserRequest");
rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns0", "https://com.user.req");
rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
doc.appendChild(rootElement);
// user element
Element user = doc.createElement("User");
rootElement.appendChild(user);
// userAttributes element
Element userAttr = doc.createElement("UserAttributes");
rootElement.appendChild(userAttr);
// name elements
Element name = doc.createElement("Name");
name.appendChild(doc.createTextNode("hello"));
userAttr.appendChild(name);
// value elements
Element value = doc.createElement("Value");
name.appendChild(doc.createTextNode("dude"));
userAttr.appendChild(value);
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<UserRequest
xmlns:ns0="https://com.user.req"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns0:UserRequest">
<User/>
<UserAttributes>
<Name>hello</Name>
<Value>dude</Value>
</UserAttributes>
</UserRequest>
Generated output:
<?xml version="1.0" encoding="UTF-8"?>
<UserRequest
xmlns:ns0="https://com.user.req"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<User/>
<UserAttributes>
<Name>hello</Name>
<Value>dude</Value>
</UserAttributes>
</UserRequest>
How to get correct namespace (as shown at expected section).
There's nothing wrong with the namespaces in your generated output. However this is an accident ... you're using setAttributeNS() to do something it's not intended for.
Read up on XML namespace declarations and namespace prefixes. That will be a lot easier than trying to explain point-by-point why you're not getting what you expected. For example, xmlns is not a namespace prefix, and xsi:type is not a namespace.
Instead of trying to create the desired namespace declarations as if they were normal attributes, delete these two lines
rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns:ns0", "https://com.user.req");
rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/",
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
and instead use
rootElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance",
"xsi:type", "ns0:UserRequest");
This should give you most of your expected output, except for the ns0 namespace prefix declaration. It won't generate that because you're not using ns0 on any element or attribute. Did you mean to have
<ns0:UserRequest ...
in your expected output?

Why is DOM doing this? (Wrong nodeName XML)

I have this XML (just a little part.. the complete xml is big)
<Root>
<Products>
<Product ID="307488">
<ClassificationReference ClassificationID="AR" Type="AgencyLink"/>
<ClassificationReference ClassificationID="AM" Type="AgencyLink">
<MetaData>
<Value AttributeID="tipoDeCompra" ID="C">Compra Centralizada</Value>
</MetaData>
</ClassificationReference>
</Product>
</Products>
</Root>
Well... I want to get the data from the line
<Value AttributeID="tipoDeCompra" ID="C">Compra Centralizada</Value>
I'm using DOM and when I use nodoValue.getTextContent() I got "Compra Centralizada" and that is ok...
But when I use nodoValue.getNodeName() I got "MetaData" but I was expecting "Value"
What is the explanations for this behaviour?
Thanks!
Your nodeValuevariable most likely points to the MetaData node, so the returned name is correct.
Note that for an element node Node.getTextContent() returns the concatenation of the text content of all child nodes. Therefore in your example the text content of the MetaData element is equal to the text content of the Value element, namely Compra Centralizada.
I guess your are getting the Node object using getElementsByTagName("MetaData"). In this case nodoValue.getTextContent() will return the text content correctly but to get the node name you need to get the child node.
Your current node must be MetaData and getTextContent() will give all the text within its opening and closing tags. This is because you are getting
Compra Centralizada
as the value. You should get the first child using getChildNodes() and then can get the Value tag.

Xml id attribute to work with Java's getElementById? [duplicate]

This question already has answers here:
Java DOM getElementByID
(2 answers)
Closed 3 years ago.
I have an xml document being parsed in Java as a w3c document.
In my xml, i have many elements of the same name, e.g <item ..... />, each one with unique attribute's value, e.g <item name="a" .... />.
I want in java to do:
doc.getElementById("a")
in order to get that specific item I have there with that name.
How can I tell java to use 'name' as the id?
Or, alternately, How can I fetch that specific item in least complexity?
DOM is not the best API to easily query your document and get back found elements. Learn XPath, which is a more appropriate API, or iterate through the tree of elements by yourself.
getElementById() will only return the element which has the given id attribute (edit: marked as such in the document DTD or schema). It can't find by name attribute.
See Java XML DOM: how are id Attributes special? for details.
You need to write a DTD that defines your attribute as being of type ID.
Well, To make a complete answer, I had to use DTD schemas like everyone stated.
Since my needs are quite simple, I added it in embedded in my xml the following way:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ATTLIST item
name ID #REQUIRED
>
]>
<root> .... </root>
The only important thing left to know is that once you declare the ATTLIST, I have to declare all of the rest of my attributes, therefore, you need to add IMPLIED:
some-attribute CDATA #IMPLIED
It says that some-attribute contains some data (can use also PCDATA for parsed cdata), and is implied, which means, it can be there or it cannot. doesnt matter.
So eventually, it'll look something like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ATTLIST item
name ID #REQUIRED
some-attribute CDATA #IMPLIED
>
]>
<root> .... </root>
And from Java side, Just use it blindly, e.g getElementById("some-name")
In order to make doc.getElementById("a") work you need to change your XML to <item id="a" name="a" .... />
If you can't change the XML, you could use XPath to retrieve this element.

Categories