In VTD-XML how to add new attribute into tag with existing attributes?

StackOverflow https://stackoverflow.com/questions/17470927

  •  02-06-2022
  •  | 
  •  

質問

I'm using VTD-XML to update XML files. In this I am trying to get a flexible way of maintaining attributes on an element. So if my original element is:

<MyElement name="myName" existattr="orig" />

I'd like to be able to update it to this:

<MyElement name="myName" existattr="new" newattr="newValue" />

I'm using a Map to manage the attribute/value pairs in my code and when I update the XML I'm doing something like the following:

private XMLModifier xm = new XMLModifier();
xm.bind(vn);

for (String key : attr.keySet()) {
     int i = vn.getAttrVal(key);

     if (i!=-1) {
         xm.updateToken(i, attr.get(key));
     } else {
         xm.insertAttribute(key+"='"+attr.get(key)+"'");
     }
}
vn = xm.outputAndReparse();

This works for updating existing attributes, however when the attribute doesn't already exist, it hits the insert (insertAttribute) and I get "ModifyException"

com.ximpleware.ModifyException: There can be only one insert per offset
at com.ximpleware.XMLModifier.insertBytesAt(XMLModifier.java:341)
at com.ximpleware.XMLModifier.insertAttribute(XMLModifier.java:1833)

My guess is that as I'm not manipulating the offset directly this might be expected. However I can see no function to insert an an attribute at a position in the element (at end).

My suspicion is that I will need to do it at the "offset" level using something like xm.insertBytesAt(int offset, byte[] content) - as this is an area I have needed to get into yet is there a way to calculate the offset at which I can insert (just before the end of the tag)?

Of course I may be mis-using VTD in some way here - if there is a better way of achieving this then happy to be directed.

Thanks

役に立ちましたか?

解決

That's an interesting limitation of the API I hadn't encountered yet. It would be great if vtd-xml-author could elaborate on technical details and why this limitation exists.

As a solution to your problem, a simple approach would be to accumulate your key-value pairs to be inserted as a String, and then to insert them in a single call after your for loop has terminated.

I've tested that this works as per your code:

private XMLModifier xm_ = new XMLModifier();
xm.bind(vn);

String insertedAttributes = "";
for (String key : attr.keySet()) {
     int i = vn.getAttrVal(key);

     if (i!=-1) {
         xm.updateToken(i, attr.get(key));
     } else {
         // Store the key-values to be inserted as attributes
         insertedAttributes += " " + key + "='" + attr.get(key) + "'";
     }
}
if (!insertedAttributes.equals("")) {
   // Insert attributes only once
   xm.insertAttribute(insertedAttributes);
}

This will also work if you need to update the attributes of multiple elements, simply nest the above code in while(autoPilot.evalXPath() != -1) and be sure to set insertedAttributes = ""; at the end of each while loop.

Hope this helps.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top