How to insert new node at specific position in XML? - java

I Have XML with this structure:
<ms:tech ID="TM_002">
<ms:wrap MDTYPE="NISOIMG" MIMETYPE="text/xml">
<ms:xmlData>
<ml:ml>
<mx:BasicInformation>
<mx:ObjectIdentifier>
<mx:objectIdentifierType>Value</mix:objectIdentifierType>
</mx:ObjectIdentifier>
**-----HERE AT THIS POSITION INSERT NEW XML TAG------**
<mx:byteOrder>Value2</mx:byteOrder>
<mx:Compression>
<mx:compressionScheme>Uncompressed</mx:compressionScheme>
</mx:Compression>
</mx:BasicInformation>
</ml:ml>
<ms:xmlData>
</ms:wrap>
</ms:tech>
I want to insert new XML tag at specific position in XML tree. My code so far looks like this:
String xp = "//ms:tech[#ID='TM_002']/ms:wrap/ms:xmlData/ml:ml/mx:BasicInformation";
List<Node> list = amdDocument.selectNodes(xp);
Node element = list.get(0);
By this I got the tag, and in this tag I want insert new one after . Im using dom4j. How can I do this? Thanks.

Related

Java appendChild (CSV to XML conversion) doesn't work for ONE node

So I need to convert a CSV file to seperate XML files (one XML file per line in the CSV file). And this all works fine, except for the fact that it refuses to add one value. It adds the other without a problem, but for some mysterious reason refuses to create a tag for one of my nodes.
Document newDoc = documentBuilder.newDocument();
Element rootElement = newDoc.createElement("XMLoutput");
newDoc.appendChild(rootElement);
String header = headers.get(col);
String value = null;
String value2 = null;
if (col < rowValues.length) {
if(header.equals("delay")) {
value = rowValues[col];
Thread.sleep(Long.parseLong(value));
}
Element shipidElement = newDoc.createElement("shipID");
shipidElement.appendChild(newDoc.createTextNode(FilenameUtils.getBaseName(csvFileName)));
rootElement.appendChild(shipidElement);
if(header.equals("centraleID")) {
value = rowValues[col];
System.out.println(value); //to check if the if condition works, it does
Element centralElement = newDoc.createElement(header);
Text child = newDoc.createTextNode(value);
centralElement.appendChild(child);
rootElement.appendChild(centralElement);
}
else if(header.equals("afstandTotKade")) {
value2 = rowValues[col];
Element curElement = newDoc.createElement(header);
curElement.appendChild(newDoc.createTextNode(value2));
rootElement.appendChild(curElement);
}
String timeStamp = new SimpleDateFormat("HH:mm:ss").format(new Date());
Element timeElement = newDoc.createElement("Timestamp");
timeElement.appendChild(newDoc.createTextNode(timeStamp));
rootElement.appendChild(timeElement);
}
So in the above code, the if loop checking for CentraleID actually works, because it prints out the values, however the XML file does not add a tag, not even if I just insert a string instead of the header value. It does, however, insert the "afstandTotKade" node and timestamp node. I am dumbfounded.
PS: this is only part of the code of course, but the problem is so minute, that it seemed superfluous to add all of it.
PPS: the code was originally the same as the others, I've just been playing around.
This is the resulting XML File btw, so the other if does add the nodes, and I know the spelling is correct in checking the header because it does print out the values (the sout code) when I run it:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<XMLoutput>
<shipID>1546312</shipID>
<afstandTotKade>1000</afstandTotKade>
<Timestamp>22:06:33</Timestamp>
</XMLoutput>

xades4j: Sign only one element

I'm using this code to sign a xml document:
Document doc = getDocument(xml_to_sign);
Element elemToSign = doc.getDocumentElement();
String file_uri_path = elemToSign.getBaseURI();
DataObjectDesc obj1 = new DataObjectReference(file_uri_path).withType("http://www.gzs.si/shemas/eslog/racun/1.5#Racun");
SignedDataObjects dataObjs = new SignedDataObjects(obj1);
signer.sign(dataObjs, elemToSign);
xml_to_sign is the full path to the xml file.
The problem is, that I would like to sign only the node with the id "data" (#data), but append the signature to the node elemToSign.
Is it possible to do this with xades4j?
Yes, it is. The sign method's argument is the parent node, not the element to sign (it could be the same node, depending on the configured references). In your example you should add a reference for "#data":
Document doc = getDocument(xml_to_sign);
Element parent = doc.getDocumentElement();
DataObjectDesc obj1 = new DataObjectReference("#data").withType("http://www.gzs.si/shemas/eslog/racun/1.5#Racun");
SignedDataObjects dataObjs = new SignedDataObjects(obj1);
signer.sign(dataObjs, parent);
Another option is to add a reference for the whole XML document (empty URI) and use a XPath transform.
You should specify that the attribute named "Id" in your xml document is the XML ID attribute that Apache Santuario (used internally by Xades4j) will use in the getElementById() (as lgoncalves has pointed out in his commments to his own answer).
Element parent = doc.getDocumentElement();
parent.setIdAttribute("Id", true);
//or parent.setIdAttributeNS("http://your.name.space", "Id", true);
I had the same problem, and this additional line of code solved it.

Google checkout java api marshaling an element rather than a string when adding AnyMultiple with setMerchantPrivateData()

This is the post cart method that I am using:
public CheckoutRedirect submit(CreateOrderRequest sku) {
CartPoster cartPoster = context.cartPoster();
CartPoster.CheckoutShoppingCartBuilder cartBuilder = cartPoster.makeCart();
Money unitPrice = new Money();
unitPrice.setCurrency(sku.getCurrency());
unitPrice.setValue(new BigDecimal(sku.getPrice()));
String platformId = sku.getPlatformId().toString();
AnyMultiple merchantPrivateData = new AnyMultiple();
merchantPrivateData.getContent().add(platformId);
MerchantCheckoutFlowSupport merchantCheckoutFlowSupport = new MerchantCheckoutFlowSupport();
merchantCheckoutFlowSupport.setContinueShoppingUrl(sku.getContinueShoppingUrl());
CheckoutShoppingCart.CheckoutFlowSupport checkoutFlowSupport = new CheckoutShoppingCart.CheckoutFlowSupport();
checkoutFlowSupport.setMerchantCheckoutFlowSupport(merchantCheckoutFlowSupport);
DigitalContent digitalcontent = new DigitalContent();
digitalcontent.setDisplayDisposition(sku.getDisplayDisposition());
digitalcontent.setDescription(sku.getDigitalContentDescription());
Item item = new Item();
item.setItemDescription(sku.getDescription());
item.setItemName(sku.getName());
item.setMerchantItemId(sku.getSkuId());
item.setUnitPrice(unitPrice);
item.setDigitalContent(digitalcontent);
item.setQuantity(sku.getQuantity());
cartBuilder.addItem(item);
CheckoutShoppingCart checkoutShoppingCart = cartBuilder.build();
checkoutShoppingCart.setCheckoutFlowSupport(checkoutFlowSupport);
checkoutShoppingCart.getShoppingCart().setMerchantPrivateData(merchantPrivateData);
return cartPoster.postCart(checkoutShoppingCart);
}
This works fine and will output xml as this:
<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
<shopping-cart>
<merchant-private-data>1000</merchant-private-data>
<items>
<item>
<digital-content>
<description>Description Goes Here</description>
<display-disposition>OPTIMISTIC</display-disposition>
</digital-content>
<item-name>Product Name</item-name>
<item-description>Product Description Goes Here</item-description>
<unit-price currency="USD">4.95</unit-price>
<quantity>1</quantity>
<merchant-item-id>87</merchant-item-id>
</item>
</items>
</shopping-cart>
<checkout-flow-support>
<merchant-checkout-flow-support>
<continue-shopping-url>http://www.example.com/success</continue-shopping-url>
</merchant-checkout-flow-support>
</checkout-flow-support>
</checkout-shopping-cart>
You will notice <merchant-private-data>1000</merchant-private-data>
If you look at the XML api tag reference for this element: http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Tag_Reference.html#tag_merchant-private-data
It states that this is a container for any well formed xml sequence and shows an example with an element within this:
<merchant-private-data>
<merchant-note>my order number 76543</merchant-note>
</merchant-private-data>
When adding the the List member in AnyMultiple, its stated that it will accept a String (as in the case I have shown) or an Element. My problem is that I cannot for the life of me, add an Element to this list without encountering marshaling errors.
I want to create:
<merchant-private-data>
<platform-id>1000</platform-id>
</merchant-private-data>
Also, I am rather new to writing Java code. Has anyone been successful in doing this using this API?
Thanks in advance.
Am not a Java dev (am .Net), so forgive my ignorance ~
You'll have to programmatically create an XML element and its value/inner text and insert/add it.
This wouldn't be part of the Google Checkout API, it would be the XML framework that handles the (de)serilialization you are already using - e.g. in .Net Framework this would be System.XML
I know it's not as helpful as can be, so I hope this at least gives you a place to look/start.

Java appending XML data

I've already read through a few of the answers on this site but none of them worked for me. I have an XML file like this:
<root>
<character>
<name>Volstvok</name>
<charID>(omitted)</charID>
<userID>(omitted)</userID>
<apiKey>(omitted)</apiKey>
</character>
</root>
I need to add another <character> somehow.
I'm trying this but it does not work:
public void addCharacter(String name, int id, int userID, String apiKey){
Element newCharacter = doc.createElement("character");
Element newName = doc.createElement("name");
newName.setTextContent(name);
Element newID = doc.createElement("charID");
newID.setTextContent(Integer.toString(id));
Element newUserID = doc.createElement("userID");
newUserID.setTextContent(Integer.toString(userID));
Element newApiKey = doc.createElement("apiKey");
newApiKey.setTextContent(apiKey);
//Setup and write
newCharacter.appendChild(newName);
newCharacter.appendChild(newID);
newCharacter.appendChild(newUserID);
newCharacter.appendChild(newApiKey);
doc.getDocumentElement().appendChild(newCharacter);
}
Without seeing all your code, I suspect the problem is that you're adjusting the in-memory DOM, but not writing the result back to the file.
Writing it out looks something like:
TransformerFactory.newInstance().newTransformer()
.transform(new DOMSource(doc),
new StreamResult(f));
where doc is a Document, and f is the File to write to.
In order to find particular elements in a DOM, I recommend XPath.

How to add a node to XML with XMLBeans XmlObject

My goal is to take an XML string and parse it with XMLBeans XmlObject and add a few child nodes.
Here's an example document (xmlString),
<?xml version="1.0"?>
<rootNode>
<person>
<emailAddress>joefoo#example.com</emailAddress>
</person>
</rootNode>
Here's the way I'd like the XML document to be after adding some nodes,
<?xml version="1.0"?>
<rootNode>
<person>
<emailAddress>joefoo#example.com</emailAddress>
<phoneNumbers>
<home>555-555-5555</home>
<work>555-555-5555</work>
<phoneNumbers>
</person>
</rootNode>
Basically, just adding the <phoneNumbers/> node with two child nodes <home/> and <work/>.
This is as far as I've gotten,
XmlObject xml = XmlObject.Factory.parse(xmlString);
Thank you
Here is an example of using the XmlCursor to insert new elements. You can also get a DOM Node for an XmlObject and using those APIs.
import org.apache.xmlbeans.*;
/**
* Adding nodes to xml using XmlCursor.
* #see http://xmlbeans.apache.org/docs/2.4.0/guide/conNavigatingXMLwithCursors.html
* #see http://xmlbeans.apache.org/docs/2.4.0/reference/org/apache/xmlbeans/XmlCursor.html
*/
public class AddNodes
{
public static final String xml =
"<rootNode>\n" +
" <person>\n" +
" <emailAddress>joefoo#example.com</emailAddress>\n" +
" </person>\n" +
"</rootNode>\n";
public static XmlOptions saveOptions = new XmlOptions().setSavePrettyPrint().setSavePrettyPrintIndent(2);
public static void main(String[] args) throws XmlException
{
XmlObject xobj = XmlObject.Factory.parse(xml);
XmlCursor cur = null;
try
{
cur = xobj.newCursor();
// We could use the convenient xobj.selectPath() or cur.selectPath()
// to position the cursor on the <person> element, but let's use the
// cursor's toChild() instead.
cur.toChild("rootNode");
cur.toChild("person");
// Move to </person> end element.
cur.toEndToken();
// Start a new <phoneNumbers> element
cur.beginElement("phoneNumbers");
// Start a new <work> element
cur.beginElement("work");
cur.insertChars("555-555-5555");
// Move past the </work> end element
cur.toNextToken();
// Or insert a new element the easy way in one step...
cur.insertElementWithText("home", "555-555-5555");
}
finally
{
if (cur != null) cur.dispose();
}
System.out.println(xobj.xmlText(saveOptions));
}
}
XMLBeans seems like a hassle, here's a solution using XOM:
import nu.xom.*;
Builder = new Builder();
Document doc = builder.build(new java.io.StringBufferInputStream(inputXml));
Nodes nodes = doc.query("person");
Element homePhone = new Element("home");
homePhone.addChild(new Text("555-555-5555"));
Element workPhone = new Element("work");
workPhone.addChild(new Text("555-555-5555"));
Element phoneNumbers = new Element("phoneNumbers");
phoneNumbers.addChild(homePhone);
phoneNumbers.addChild(workPhone);
nodes[0].addChild(phoneNumbers);
System.out.println(doc.toXML()); // should print modified xml
It may be a little difficult to manipulate the objects using just the XmlObject interface. Have you considered generating the XMLBEANS java objects from this xml?
If you don't have XSD for this schema you can generate it using XMLSPY or some such tools.
If you just want XML manipulation (i.e, adding nodes) you could try some other APIs like jdom or xstream or some such thing.
Method getDomNode() gives you access to the underlying W3C DOM Node. Then you can append childs using W3C Document interface.

Categories

Resources