Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor / Improve support of schema having sibling elements for translation #8540

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 54 additions & 12 deletions core/src/main/java/org/fao/geonet/kernel/EditLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//=== EditLib
//===
//=============================================================================
//=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
//=== Copyright (C) 2001-2024 Food and Agriculture Organization of the
//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
//=== and United Nations Environment Programme (UNEP)
//===
Expand Down Expand Up @@ -35,7 +35,6 @@
import java.io.StringReader;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.collections.CollectionUtils;
Expand All @@ -50,6 +49,7 @@
import org.fao.geonet.kernel.schema.MetadataAttribute;
import org.fao.geonet.kernel.schema.MetadataSchema;
import org.fao.geonet.kernel.schema.MetadataType;
import org.fao.geonet.kernel.schema.MultilingualSchemaPlugin;
import org.fao.geonet.kernel.schema.SchemaPlugin;
import org.fao.geonet.utils.Xml;
import org.jaxen.JaxenException;
Expand Down Expand Up @@ -223,6 +223,47 @@ public Element addElement(MetadataSchema mdSchema, Element el, String qname) thr
return child;
}

/**
* Creates an element with a name (qname) as child of an element (el).
*
* If the element to create is multilingual and the related metadata schemas requires to duplicate it,
* one child per metadata language is added.
*
* See {@link org.fao.geonet.kernel.schema.MultilingualSchemaPlugin#duplicateElementsForMultilingual()}
*
* @param mdSchema Metadata schema
* @param el Parent element to add the new element.
* @param qname Name of the new element to add.
* @param languages Languages to add to the new elements.
* @return List of child elements added. For non-multilingual, contains 1 element.
* @throws Exception
*/
public List<Element> addElements(MetadataSchema mdSchema, Element el,
String qname, List<String> languages) throws Exception {

List<Element> result = new ArrayList<>();

if (mdSchema.getSchemaPlugin() instanceof MultilingualSchemaPlugin) {
MultilingualSchemaPlugin multilingualSchemaPlugin = (MultilingualSchemaPlugin) mdSchema.getSchemaPlugin();

if (!languages.isEmpty() &&
multilingualSchemaPlugin.duplicateElementsForMultilingual() &&
multilingualSchemaPlugin.isMultilingualElementType(mdSchema.getElementType(qname, el.getName()))) {
for(String language : languages) {
Element child = addElement(mdSchema, el, qname);
((MultilingualSchemaPlugin) mdSchema.getSchemaPlugin()).addTranslationToElement(child, language, "");
result.add(child);
}
return result;
}
}

// If no multilingual management is required, process the single element.
result.add(addElement(mdSchema, el, qname));

return result;
}

/**
* Adds XML fragment to the metadata record in the last element of the type of the element in
* its parent.
Expand Down Expand Up @@ -968,7 +1009,7 @@ public void clearVersion(String id) {
//--------------------------------------------------------------------------

private List<Element> filterOnQname(List<Element> children, String qname) {
Vector<Element> result = new Vector<Element>();
Vector<Element> result = new Vector<>();
for (Element child : children) {
if (child.getQualifiedName().equals(qname)) {
result.add(child);
Expand Down Expand Up @@ -1166,7 +1207,7 @@ public List<Element> searchChildren(String chName, Element md, String schema) th
//

boolean hasContent = false;
Vector<Element> holder = new Vector<Element>();
Vector<Element> holder = new Vector<>();

MetadataSchema mdSchema = scm.getSchema(schema);
String chUQname = getUnqualifiedName(chName);
Expand Down Expand Up @@ -1222,12 +1263,12 @@ public void expandElements(String schema, Element md) throws Exception {
MetadataType thisType = mdSchema.getTypeInfo(typeName);

if (thisType.hasContainers) {
Vector<Content> holder = new Vector<Content>();
Vector<Content> holder = new Vector<>();

for (String chName: thisType.getAlElements()) {
if (edit_CHOICE_GROUP_SEQUENCE_in(chName)) {
List<Element> elems = searchChildren(chName, md, schema);
if (elems.size() > 0) {
if (!elems.isEmpty()) {
holder.addAll(elems);
}
} else {
Expand All @@ -1246,7 +1287,7 @@ public void expandElements(String schema, Element md) throws Exception {
* For each container element - descend and collect children.
*/
private Vector<Object> getContainerChildren(Element md) {
Vector<Object> result = new Vector<Object>();
Vector<Object> result = new Vector<>();

@SuppressWarnings("unchecked")
List<Element> chChilds = md.getChildren();
Expand All @@ -1268,17 +1309,17 @@ private Vector<Object> getContainerChildren(Element md) {
public void contractElements(Element md) {
//--- contract container children at each level in the XML tree

Vector<Object> children = new Vector<Object>();
Vector<Object> children = new Vector<>();
@SuppressWarnings("unchecked")
List<Content> childs = md.getContent();
for (Content obj : childs) {
if (obj instanceof Element) {
Element mdCh = (Element) obj;
String mdName = mdCh.getName();
if (edit_CHOICE_GROUP_SEQUENCE_in(mdName)) {
if (mdCh.getChildren().size() > 0) {
if (!mdCh.getChildren().isEmpty()) {
Vector<Object> chChilds = getContainerChildren(mdCh);
if (chChilds.size() > 0) {
if (!chChilds.isEmpty()) {
children.addAll(chChilds);
}
}
Expand Down Expand Up @@ -1525,7 +1566,7 @@ private void insertLast(Element md, String childName, String childNS, Element ch
@SuppressWarnings("unchecked")
List<Element> list = md.getChildren();

List<Element> v = new ArrayList<Element>();
List<Element> v = new ArrayList<>();

for (int i = 0; i < list.size(); i++) {
Element el = list.get(i);
Expand Down Expand Up @@ -1606,7 +1647,8 @@ public Element createElement(String schema, Element child, Element parent) throw
MetadataSchema mds = scm.getSchema(schema);
MetadataType mdt = getType(mds, parent);

int min = -1, max = -1;
int min = -1;
int max = -1;

for (int i = 0; i < mdt.getElementCount(); i++) {
if (childQName.equals(mdt.getElementAt(i))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.fao.geonet.kernel.schema.LinkPatternStreamer.RawLinkPatternStreamer;
import org.fao.geonet.utils.Log;
import org.fao.geonet.utils.Xml;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
Expand Down Expand Up @@ -579,6 +580,31 @@ public Element processElement(Element el,

}

@Override
public boolean duplicateElementsForMultilingual() {
return false;
}

@Override
public List<String> getMetadataLanguages(Element metadata) {
try {
return Xml.selectNodes(metadata, ".//*[name() = 'mdb:defaultLocale' or name() = 'mdb:otherLocale']/lan:PT_Locale/@id", allNamespaces.asList())
.stream()
.filter(Attribute.class::isInstance)
.map(node -> ((Attribute)node).getValue())
.filter(s -> s != null && !s.isBlank())
.collect(Collectors.toList());
} catch (JDOMException ignored) {
}
return Collections.emptyList();
}

@Override
public boolean isMultilingualElementType(String elementType) {
// Not required in ISO schemas, only required for schemas where duplicateElementsForMultilingual returns true.
return false;
}

/**
* Checks if an element requires processing in {@link #processElement(Element, String, String, String)}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,31 @@ public Element processElement(Element el,

}

@Override
public boolean duplicateElementsForMultilingual() {
return false;
}

@Override
public List<String> getMetadataLanguages(Element metadata) {
try {
return Xml.selectNodes(metadata, ".//gmd:locale/gmd:PT_Locale/@id", allNamespaces.asList())
.stream()
.filter(Attribute.class::isInstance)
.map(node -> ((Attribute)node).getValue())
.filter(s -> s != null && !s.isBlank())
.collect(Collectors.toList());
} catch (JDOMException ignored) {
}
return Collections.emptyList();
}

@Override
public boolean isMultilingualElementType(String elementType) {
// Not required in ISO schemas, only required for schemas where duplicateElementsForMultilingual returns true.
return false;
}

/**
* Checks if an element requires processing in {@link #processElement(Element, String, String, String)}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.jdom.Element;
import org.jdom.JDOMException;

import java.util.ArrayList;
import java.util.List;

/**
Expand All @@ -40,8 +41,66 @@ public interface MultilingualSchemaPlugin {
*/
public abstract List<Element> getTranslationForElement(Element element, String languageIdentifier);

/**
* Updates an element with the related multilingual information using the language and value provided.
*
* @param element XML element to update.
* @param languageIdentifier Language identifier.
* @param value Value for the element.
*/
public abstract void addTranslationToElement(Element element, String languageIdentifier, String value);

/**
* Remove all multilingual aspect of an element.
*
* @param element XML element to update.
* @param mdLang Metadata languages.
* @return
* @throws JDOMException
*/
public abstract Element removeTranslationFromElement(Element element, List<String> mdLang) throws JDOMException;

/**
* Retrieves the list of metadata languages used in the metadata.
* @param metadata
* @return
*/
public abstract List<String> getMetadataLanguages(Element metadata);

/**
* Checks if an element type is multilingual. For example, in DCAT schema, rdf:PlainLiteral type.
*
* @param elementType Element type to check.
* @return true if the element type is multilingual, otherwise false.
*/
public abstract boolean isMultilingualElementType(String elementType);


/**
* Flag to indicate when adding an element to the metadata editor, if should be duplicated for each metadata language.
* For example, in DCAT schema adding vcard:organization-name in a metadata that has English and French languages
* (similar case for Dublin Core), should duplicate the element for each language:
*
* <vcard:organization-name xml:lang="en"/>
* <vcard:organization-name xml:lang="fr"/>
*
* For ISO profiles should be set to false, as the multilingual elements are not duplicated. Multilingual values
* are added as children elements, requiring a different processing. Adding gmd:organisationName in a metadata
* that has English and French languages:
*
* <gmd:organisationName xsi:type="gmd:PT_FreeText_PropertyType">
* <gco:CharacterString></gco:CharacterString>
* <gmd:PT_FreeText>
* <gmd:textGroup>
* <gmd:LocalisedCharacterString locale="#EN"></gmd:LocalisedCharacterString>
* </gmd:textGroup>
* <gmd:textGroup>
* <gmd:LocalisedCharacterString locale="#FR"></gmd:LocalisedCharacterString>
* </gmd:textGroup>
* </gmd:PT_FreeText>
* </gmd:organisationName>
*
* @return
*/
public abstract boolean duplicateElementsForMultilingual();
}
Loading
Loading