Skip to content

Commit

Permalink
API / Batch editing / XPath / Add support for attribute with namespace.
Browse files Browse the repository at this point in the history
eg. The following was failing to remove `gco:nilReason` attribute:

```json
{
  "field":"XPath_1",
  "insertMode":"gn_delete",
  "xpath":".//gmd:pointOfContact[gmd:CI_ResponsibleParty/gmd:contactInfo/*/gmd:address/*/gmd:electronicMailAddress/gco:CharacterString = '[email protected]']/@gco:nilReason[. = 'withheld']",
  "condition":"",
  "value":"",
  "isXpath":true}
```
  • Loading branch information
fxprunayre committed Oct 30, 2023
1 parent af8566e commit e2be3a7
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 4 deletions.
28 changes: 24 additions & 4 deletions core/src/main/java/org/fao/geonet/kernel/EditLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.commons.jxpath.ri.parser.Token;
import org.apache.commons.jxpath.ri.parser.XPathParser;
import org.apache.commons.jxpath.ri.parser.XPathParserConstants;
import org.apache.commons.lang.StringUtils;
import org.fao.geonet.constants.Edit;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.Pair;
Expand Down Expand Up @@ -583,7 +584,10 @@ public boolean addElementOrFragmentFromXpath(Element metadataRecord,
}
} else if (propNode instanceof Attribute) {
Element parent = ((Attribute) propNode).getParent();
parent.removeAttribute(((Attribute) propNode).getName());
Attribute targetAttribute = (Attribute) propNode;
parent.removeAttribute(
targetAttribute.getName(),
targetAttribute.getNamespace());
}
} else {
// Update element content with node
Expand Down Expand Up @@ -736,6 +740,7 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met
boolean isAttribute = false;
String currentElementName = "";
String currentElementNamespacePrefix = "";
String currentAttributeNamespacePrefix = "";

// Stop when token is null, start of an expression is found ie. "["
//
Expand All @@ -758,10 +763,15 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met
isAttribute = true;
}
// Match namespace prefix
if (currentToken.kind == XPathParserLocalConstants.TEXT && previousToken.kind == XPathParserConstants.SLASH) {
if (currentToken.kind == XPathParserLocalConstants.TEXT &&
previousToken.kind == XPathParserConstants.SLASH) {
// get element namespace if element is text and previous was /
// means qualified name only is supported
currentElementNamespacePrefix = currentToken.image;
} else if (isAttribute &&
previousToken.kind == XPathParserLocalConstants.TEXT &&
currentToken.kind == XPathParserLocalConstants.NAMESPACE_SEP) {
currentAttributeNamespacePrefix = previousToken.image;
} else if (currentToken.kind == XPathParserLocalConstants.TEXT &&
previousToken.kind == XPathParserLocalConstants.NAMESPACE_SEP) {
// get element name if element is text and previous was /
Expand All @@ -788,7 +798,9 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met
} else {
LOGGER_ADD_ELEMENT.debug(" > add new node {} inserted in {}", qualifiedName, currentNode.getName());

if (metadataSchema.getElementValues(qualifiedName, currentNode.getQualifiedName()) != null) {
if (isAttribute) {
existingElement = false; // Attribute is created and set after.
} else if (metadataSchema.getElementValues(qualifiedName, currentNode.getQualifiedName()) != null) {
currentNode = addElement(metadataSchema, currentNode, qualifiedName);
existingElement = false;
} else {
Expand Down Expand Up @@ -833,7 +845,15 @@ private boolean createAndAddFromXPath(Element metadataRecord, MetadataSchema met
doAddFragmentFromXpath(metadataSchema, value.getNodeValue(), currentNode);
} else {
if (isAttribute) {
currentNode.setAttribute(previousToken.image, value.getStringValue());
if (StringUtils.isNotEmpty(currentAttributeNamespacePrefix)) {
currentNode.setAttribute(previousToken.image,
value.getStringValue(),
Namespace.getNamespace(currentAttributeNamespacePrefix,
metadataSchema.getNS(currentAttributeNamespacePrefix)));
} else {
currentNode.setAttribute(previousToken.image, value.getStringValue());
}

} else {
currentNode.setText(value.getStringValue());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.fao.geonet.domain.AbstractMetadata;
import org.fao.geonet.kernel.datamanager.IMetadataUtils;
import org.fao.geonet.kernel.mef.MEFLibIntegrationTest;
import org.fao.geonet.schema.iso19115_3_2018.ISO19115_3_2018Namespaces;
import org.fao.geonet.services.AbstractServiceIntegrationTest;
import org.jdom.Attribute;
import org.jdom.Element;
Expand Down Expand Up @@ -322,6 +323,66 @@ public void testUpdateRecordAddAttribute() throws Exception {
Assert.assertEquals("value", ((Element) scope.get(0)).getAttributeValue("newAttribute"));
}

@Test
public void testUpdateRecordAddAndDeleteAttributeWithNamespace() throws Exception {
final String uuid = "db07463b-6769-401e-944b-f22e2e3bcc26";
BatchEditParameter[] listOfupdates = new BatchEditParameter[]{
new BatchEditParameter(
"/mdb:MD_Metadata/mdb:metadataScope/@gco:nilReason",
"<gn_add>withheld</gn_add>"
)
};

this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.mockHttpSession = loginAsAdmin();

Gson gson = new GsonBuilder()
.create();
JsonElement jsonEl = gson.toJsonTree(listOfupdates);

this.mockMvc.perform(put("/srv/api/records/batchediting?uuids=" + uuid)
.content(jsonEl.toString())
.contentType(MediaType.APPLICATION_JSON)
.session(this.mockHttpSession)
.accept(MediaType.parseMediaType("application/json")))
.andExpect(status().is(201));

AbstractMetadata updatedRecord = repository.findOneByUuid(uuid);
Element xml = Xml.loadString(updatedRecord.getData(), false);

List scope = org.fao.geonet.utils.Xml.selectNodes(xml,
"./mdb:metadataScope",
xml.getAdditionalNamespaces());
Assert.assertEquals("withheld", ((Element) scope.get(0)).getAttributeValue("nilReason", ISO19115_3_2018Namespaces.GCO));


listOfupdates = new BatchEditParameter[]{
new BatchEditParameter(
"/mdb:MD_Metadata/mdb:metadataScope/@gco:nilReason",
"<gn_delete/>"
)
};

jsonEl = gson.toJsonTree(listOfupdates);

this.mockMvc.perform(put("/srv/api/records/batchediting?uuids=" + uuid)
.content(jsonEl.toString())
.contentType(MediaType.APPLICATION_JSON)
.session(this.mockHttpSession)
.accept(MediaType.parseMediaType("application/json")))
.andExpect(status().is(201));

updatedRecord = repository.findOneByUuid(uuid);
xml = Xml.loadString(updatedRecord.getData(), false);

scope = org.fao.geonet.utils.Xml.selectNodes(xml,
"./mdb:metadataScope/gco:nilReason",
xml.getAdditionalNamespaces());
Assert.assertEquals(0, scope.size());

}


@Test
public void testUpdateRecordElement() throws Exception {
final String uuid = "db07463b-6769-401e-944b-f22e2e3bcc26";
Expand Down

0 comments on commit e2be3a7

Please sign in to comment.