NIHVIVO-143 Allow adding a new moniker from the front end

This commit is contained in:
rjy7 2010-03-22 23:17:22 +00:00
parent 87a97cd8df
commit bcbe290c51
10 changed files with 146 additions and 39 deletions

View file

@ -2,6 +2,11 @@
package edu.cornell.mannlib.vitro.webapp.dao; package edu.cornell.mannlib.vitro.webapp.dao;
import java.util.Arrays;
import java.util.List;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.XSD;
import com.hp.hpl.jena.ontology.AnnotationProperty; import com.hp.hpl.jena.ontology.AnnotationProperty;
public class VitroVocabulary { public class VitroVocabulary {
@ -279,4 +284,27 @@ public class VitroVocabulary {
public static final String ONTOLOGY_PREFIX_ANNOT = vitroURI + "ontologyPrefixAnnot"; public static final String ONTOLOGY_PREFIX_ANNOT = vitroURI + "ontologyPrefixAnnot";
public static final List<String> VITRO_NS_PROPERTIES = Arrays.asList(BLURB, CITATION, DESCRIPTION, LABEL, LINK_ANCHOR, MONIKER, PRIMARY_LINK, RDF_TYPE, TIMEKEY);
public static String getVitroNsPropDatatypeUri(String propName) {
Resource datatype = propName == TIMEKEY ? XSD.dateTime : XSD.xstring;
return datatype.getURI();
}
// public static final Map<String, String> VITRO_NS_PROPERTIES = new HashMap<String, String>() {
// {
// put(BLURB, XSD.xstring.getURI());
// put(CITATION, XSD.xstring.getURI());
// put(DESCRIPTION, XSD.xstring.getURI());
// put(LABEL, XSD.xstring.getURI());
// put(LINK_ANCHOR, XSD.xstring.getURI());
// put(MONIKER, XSD.xstring.getURI());
// put(PRIMARY_LINK, XSD.xstring.getURI());
// put(RDF_TYPE, XSD.xstring.getURI());
// put(TIMEKEY, XSD.dateTime.getURI());
// }
// };
} }

View file

@ -86,11 +86,11 @@ public class RdfLiteralHash {
// RY Instead of a code fork here, we should have a method of Individual getAllDataPropertyStatements() which // RY Instead of a code fork here, we should have a method of Individual getAllDataPropertyStatements() which
// doesn't filter out the vitro ns property statements. This would also simplify the front end editing of the vitro ns // doesn't filter out the vitro ns property statements. This would also simplify the front end editing of the vitro ns
// properties, because they wouldn't have to be a special case. // properties, because they wouldn't have to be a special case.
public static DataPropertyStatement getPropertyStmtByHash(Individual ind, int hash, Model model, boolean isVitroNsProp) { public static DataPropertyStatement getPropertyStmtByHash(Individual ind, String predicateUri, int hash, Model model, boolean isVitroNsProp) {
if (ind == null) return null; if (ind == null) return null;
DataPropertyStatement dps = isVitroNsProp ? RdfLiteralHash.getVitroNsPropertyStmtByHash(ind, model, hash) : DataPropertyStatement dps = isVitroNsProp ? RdfLiteralHash.getVitroNsPropertyStmtByHash(ind, predicateUri, model, hash) :
RdfLiteralHash.getDataPropertyStmtByHash(ind, hash); RdfLiteralHash.getDataPropertyStmtByHash(ind, hash);
return dps; return dps;
@ -114,10 +114,12 @@ public class RdfLiteralHash {
* @param hash * @param hash
* @return a DataPropertyStatement if found or null if not found * @return a DataPropertyStatement if found or null if not found
*/ */
public static DataPropertyStatement getVitroNsPropertyStmtByHash(Individual ind, Model model, int hash) { public static DataPropertyStatement getVitroNsPropertyStmtByHash(Individual ind, String predicateUri, Model model, int hash) {
DataPropertyStatement dps = null; DataPropertyStatement dps = null;
StmtIterator stmts = model.listStatements(model.createResource(ind.getURI()), null, (RDFNode)null); StmtIterator stmts = model.listStatements(model.createResource(ind.getURI()),
model.getProperty(predicateUri),
(RDFNode)null);
try { try {
while (stmts.hasNext()) { while (stmts.hasNext()) {
Statement stmt = stmts.nextStatement(); Statement stmt = stmts.nextStatement();

View file

@ -21,6 +21,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
import edu.cornell.mannlib.vitro.webapp.auth.identifier.ServletIdentifierBundleFactory; import edu.cornell.mannlib.vitro.webapp.auth.identifier.ServletIdentifierBundleFactory;
@ -133,9 +135,15 @@ public class PropertyEditLinks extends TagSupport{
} else if( item instanceof DataProperty ){ } else if( item instanceof DataProperty ){
DataProperty prop = (DataProperty)item; // a DataProperty populated for this subject individual DataProperty prop = (DataProperty)item; // a DataProperty populated for this subject individual
links = doDataProp( prop, entity, themeDir,policyToAccess(ids, policy, entity.getURI(), prop), contextPath ) ; links = doDataProp( prop, entity, themeDir,policyToAccess(ids, policy, entity.getURI(), prop), contextPath ) ;
} else if (item instanceof String && data != null) { } else if (item instanceof String && isVitroNsProp((String) item)) {
DataPropertyStatement dps = (DataPropertyStatement) new DataPropertyStatementImpl(entity.getURI(), (String)item, data); String subjectUri = entity.getURI();
links = doVitroNamespaceProp( dps, entity, themeDir, policyToAccess(ids, policy, dps), contextPath ); if (data != null) { // links to edit or delete an existing value
DataPropertyStatement dps = (DataPropertyStatement) new DataPropertyStatementImpl(subjectUri, (String)item, data);
links = doVitroNamespacePropStmt( dps, entity, themeDir, policyToAccess(ids, policy, dps), contextPath );
} else { // link to add a new value
links = doVitroNsProp( subjectUri, (String)item, themeDir, policyToAccess(ids, policy, subjectUri, (String)item), contextPath ) ;
}
} else { } else {
log.error("PropertyEditLinks cannot make links for an object of type "+item.getClass().getName()); log.error("PropertyEditLinks cannot make links for an object of type "+item.getClass().getName());
return SKIP_BODY; return SKIP_BODY;
@ -161,6 +169,10 @@ public class PropertyEditLinks extends TagSupport{
return SKIP_BODY; return SKIP_BODY;
} }
private boolean isVitroNsProp(String predicateUri) {
return VitroVocabulary.VITRO_NS_PROPERTIES.contains(predicateUri);
}
protected LinkStruct[] doDataProp(DataProperty dprop, Individual entity, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) { protected LinkStruct[] doDataProp(DataProperty dprop, Individual entity, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) {
if( allowedAccessTypeArray == null || dprop == null || allowedAccessTypeArray.length == 0 ) { if( allowedAccessTypeArray == null || dprop == null || allowedAccessTypeArray.length == 0 ) {
log.debug("null or empty access type array in doDataProp for dprop "+dprop.getPublicName()+"; most likely just a property prohibited from editing"); log.debug("null or empty access type array in doDataProp for dprop "+dprop.getPublicName()+"; most likely just a property prohibited from editing");
@ -188,6 +200,39 @@ public class PropertyEditLinks extends TagSupport{
return links; return links;
} }
protected LinkStruct[] doVitroNsProp(String subjectUri, String propertyUri, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) {
if( allowedAccessTypeArray == null || subjectUri == null || allowedAccessTypeArray.length == 0 ) {
log.debug("null or empty access type array in doDataProp for vitro namespace property " + propertyUri + "; most likely just a property prohibited from editing");
return empty_array;
}
LinkStruct[] links = new LinkStruct[1];
Model model = (Model)pageContext.getServletContext().getAttribute("jenaOntModel");
StmtIterator stmts = model.listStatements(model.createResource(subjectUri),
model.getProperty(propertyUri),
(RDFNode) null);
if (stmts.hasNext()) {
log.debug("not showing an \"add\" link for vitro namespace property " + propertyUri + " because it has a limit of 1");
} else {
if( contains( allowedAccessTypeArray, EditLinkAccess.ADDNEW ) ){
log.debug("vitro namespace property "+propertyUri+" gets an \"add\" link");
String url = makeRelativeHref(contextPath + "edit/editDatapropStmtRequestDispatch.jsp",
"subjectUri", subjectUri,
"predicateUri", propertyUri,
"vitroNsProp", "true");
LinkStruct ls = new LinkStruct();
ls.setHref( url );
ls.setType("add");
ls.setMouseoverText("add a new entry");
links[0] = ls;
} else {
log.debug("no add link generated for vitro namespace property "+propertyUri);
}
}
return links;
}
protected LinkStruct[] doObjProp(ObjectProperty oprop, Individual entity, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) { protected LinkStruct[] doObjProp(ObjectProperty oprop, Individual entity, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) {
if( allowedAccessTypeArray == null || oprop == null || allowedAccessTypeArray.length == 0 ) { if( allowedAccessTypeArray == null || oprop == null || allowedAccessTypeArray.length == 0 ) {
@ -308,7 +353,7 @@ public class PropertyEditLinks extends TagSupport{
return links; return links;
} }
protected LinkStruct[] doVitroNamespaceProp(DataPropertyStatement dpropStmt, Individual subject, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) { protected LinkStruct[] doVitroNamespacePropStmt(DataPropertyStatement dpropStmt, Individual subject, String themeDir, EditLinkAccess[] allowedAccessTypeArray, String contextPath) {
if( allowedAccessTypeArray == null || dpropStmt == null || allowedAccessTypeArray.length == 0 ) { if( allowedAccessTypeArray == null || dpropStmt == null || allowedAccessTypeArray.length == 0 ) {
log.debug("Null or empty access type array for vitro namespace property " + dpropStmt.getDatapropURI()); log.debug("Null or empty access type array for vitro namespace property " + dpropStmt.getDatapropURI());
@ -481,9 +526,16 @@ public class PropertyEditLinks extends TagSupport{
} }
protected EditLinkAccess[] policyToAccess( IdentifierBundle ids, PolicyIface policy, String subjectUri, DataProperty item) { protected EditLinkAccess[] policyToAccess( IdentifierBundle ids, PolicyIface policy, String subjectUri, DataProperty item) {
String propertyUri = item.getURI();
return policyToAccess(ids, policy, subjectUri, propertyUri);
}
protected EditLinkAccess[] policyToAccess( IdentifierBundle ids, PolicyIface policy, String subjectUri, String propertyUri) {
EditLinkAccess[] access; EditLinkAccess[] access;
RequestedAction action = new AddDataPropStmt(subjectUri, item.getURI(), RequestActionConstants.SOME_LITERAL, null, null); RequestedAction action = new AddDataPropStmt(subjectUri, propertyUri, RequestActionConstants.SOME_LITERAL, null, null);
PolicyDecision dec = policy.isAuthorized(ids, action); PolicyDecision dec = policy.isAuthorized(ids, action);
if( dec != null && dec.getAuthorized() == Authorization.AUTHORIZED ){ if( dec != null && dec.getAuthorized() == Authorization.AUTHORIZED ){

View file

@ -202,8 +202,10 @@ public class RdfLiteralHashTest {
Individual bob = new IndividualImpl(); Individual bob = new IndividualImpl();
bob.setURI("http://example.com/bob"); bob.setURI("http://example.com/bob");
int hash = RdfLiteralHash.makeVitroNsLiteralHash(bob,VitroVocabulary.MONIKER, "great", model); String propertyUri = VitroVocabulary.MONIKER;
DataPropertyStatement stmt = RdfLiteralHash.getVitroNsPropertyStmtByHash(bob, model, hash);
int hash = RdfLiteralHash.makeVitroNsLiteralHash(bob, propertyUri, "great", model);
DataPropertyStatement stmt = RdfLiteralHash.getVitroNsPropertyStmtByHash(bob, propertyUri, model, hash);
String data = stmt.getData(); String data = stmt.getData();
String datatypeUri = stmt.getDatatypeURI(); String datatypeUri = stmt.getDatatypeURI();

View file

@ -113,7 +113,7 @@
DataPropertyStatement dps = null; DataPropertyStatement dps = null;
if( dataHash != 0) { if( dataHash != 0) {
Model model = (Model)application.getAttribute("jenaOntModel"); Model model = (Model)application.getAttribute("jenaOntModel");
dps = RdfLiteralHash.getPropertyStmtByHash(subject, dataHash, model, isVitroNsProp); dps = RdfLiteralHash.getPropertyStmtByHash(subject, predicateUri, dataHash, model, isVitroNsProp);
if (dps==null) { if (dps==null) {
log.error("No match to existing data property \""+predicateUri+"\" statement for subject \""+subjectUri+"\" via key "+datapropKeyStr); log.error("No match to existing data property \""+predicateUri+"\" statement for subject \""+subjectUri+"\" via key "+datapropKeyStr);

View file

@ -65,7 +65,7 @@
String vitroNsProp = vreq.getParameter("vitroNsProp"); String vitroNsProp = vreq.getParameter("vitroNsProp");
boolean isVitroNsProp = vitroNsProp != null && vitroNsProp.equals("true") ? true : false; boolean isVitroNsProp = vitroNsProp != null && vitroNsProp.equals("true") ? true : false;
DataPropertyStatement dps = RdfLiteralHash.getPropertyStmtByHash(subject, dataHash, model, isVitroNsProp); DataPropertyStatement dps = RdfLiteralHash.getPropertyStmtByHash(subject, predicateUri, dataHash, model, isVitroNsProp);
if( log.isDebugEnabled() ){ if( log.isDebugEnabled() ){
log.debug("attempting to delete dataPropertyStatement: subjectURI <" + dps.getIndividualURI() +">"); log.debug("attempting to delete dataPropertyStatement: subjectURI <" + dps.getIndividualURI() +">");

View file

@ -68,7 +68,7 @@
vreq.setAttribute("rangeLangJson", rangeLang); vreq.setAttribute("rangeLangJson", rangeLang);
} }
} else { } else {
log.debug("No incoming dataproperty statement attribute for property "+prop.getPublicName()+", adding a new statement"); log.debug("No incoming dataproperty statement attribute for property "+prop.getPublicName()+"; adding a new statement");
if(rangeDatatypeUri != null && rangeDatatypeUri.length() > 0) { if(rangeDatatypeUri != null && rangeDatatypeUri.length() > 0) {
String defaultVal = defaultsForXSDtypes.get(rangeDatatypeUri); String defaultVal = defaultsForXSDtypes.get(rangeDatatypeUri);
if( defaultVal == null ) if( defaultVal == null )

View file

@ -2,6 +2,7 @@
<%@ page import="java.util.ArrayList"%> <%@ page import="java.util.ArrayList"%>
<%@ page import="java.util.Arrays"%> <%@ page import="java.util.Arrays"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="com.hp.hpl.jena.rdf.model.Literal"%> <%@ page import="com.hp.hpl.jena.rdf.model.Literal"%>
<%@ page import="com.hp.hpl.jena.rdf.model.Model"%> <%@ page import="com.hp.hpl.jena.rdf.model.Model"%>
@ -30,6 +31,8 @@
String subjectUri = vreq.getParameter("subjectUri"); String subjectUri = vreq.getParameter("subjectUri");
String predicateUri = vreq.getParameter("predicateUri"); String predicateUri = vreq.getParameter("predicateUri");
String propertyName = predicateUri.substring(predicateUri.lastIndexOf("#")+1);
vreq.setAttribute("propertyName", propertyName);
DataPropertyStatement dps = (DataPropertyStatement)vreq.getAttribute("dataprop"); DataPropertyStatement dps = (DataPropertyStatement)vreq.getAttribute("dataprop");
@ -42,16 +45,43 @@
Model model = (Model)application.getAttribute("jenaOntModel"); Model model = (Model)application.getAttribute("jenaOntModel");
String rangeDatatypeUri = dps.getDatatypeURI(); // Get datatype and language for the data property statement
String rangeDatatypeUriJson = MiscWebUtils.escape(rangeDatatypeUri); String rangeDatatypeUri = null,
rangeLang = null;
if (dps != null) {
rangeDatatypeUri = dps.getDatatypeURI();
if (rangeDatatypeUri == null) {
log.debug("no range datatype uri set on vitro namespace property statement for property " + predicateUri + " in defaultVitroNsPropForm.jsp");
} else {
log.debug("range datatype uri of [" + rangeDatatypeUri + "] on vitro namespace property statement for property " + predicateUri + " in defaultVitroNsPropForm.jsp");
}
rangeLang = dps.getLanguage();
if( rangeLang == null ) {
log.debug("no language attribute on vitro namespace property statement for property " + predicateUri + " in defaultVitroNsPropForm.jsp");
rangeLang = "";
} else {
log.debug("language attribute of ["+rangeLang+"] on vitro namespace property statement for property " + predicateUri + " in defaultVitroNsPropForm.jsp");
}
} else {
log.debug("No incoming vitro namespace property statement for property "+predicateUri+"; adding a new statement");
rangeDatatypeUri = VitroVocabulary.getVitroNsPropDatatypeUri(predicateUri);
}
String rangeDatatypeUriJson = rangeDatatypeUri == null ? "" : MiscWebUtils.escape(rangeDatatypeUri);
vreq.setAttribute("rangeDatatypeUriJson", rangeDatatypeUriJson); vreq.setAttribute("rangeDatatypeUriJson", rangeDatatypeUriJson);
vreq.setAttribute("rangeLangJson", rangeLang);
// Create list of validators
ArrayList<String> validatorList = new ArrayList<String>(); ArrayList<String> validatorList = new ArrayList<String>();
if (predicateUri.equals(VitroVocabulary.LABEL) || predicateUri.equals(VitroVocabulary.RDF_TYPE)) { if (predicateUri.equals(VitroVocabulary.LABEL) || predicateUri.equals(VitroVocabulary.RDF_TYPE)) {
validatorList.add("nonempty"); validatorList.add("nonempty");
} }
if (!rangeDatatypeUriJson.isEmpty()) { if (!StringUtils.isEmpty(rangeDatatypeUriJson)) {
validatorList.add("datatype:" + rangeDatatypeUriJson); validatorList.add("datatype:" + rangeDatatypeUriJson);
} }
vreq.setAttribute("validators", StringUtils.quotedList(validatorList, ",")); vreq.setAttribute("validators", StringUtils.quotedList(validatorList, ","));
@ -59,7 +89,6 @@
%> %>
<c:set var="predicate" value="<%=predicateUri%>" /> <c:set var="predicate" value="<%=predicateUri%>" />
<c:set var="propertyName" value="${fn:substringAfter(predicate, '#')}" />
<%-- Then enter a SPARQL query for the field, by convention concatenating the field id with "Existing" <%-- Then enter a SPARQL query for the field, by convention concatenating the field id with "Existing"
to convey that the expression is used to retrieve any existing value for the field in an existing individual. to convey that the expression is used to retrieve any existing value for the field in an existing individual.
@ -77,13 +106,6 @@
?subject <${predicate}> ?${propertyName} . ?subject <${predicate}> ?${propertyName} .
</v:jsonset> </v:jsonset>
<%
%>
<c:if test="${propertyName == 'label' || propertyName == 'type'}">
<c:set var="validator" value="nonempty" scope="request" />
</c:if>
<c:set var="editjson" scope="request"> <c:set var="editjson" scope="request">
{ {
"formUrl" : "${formUrl}", "formUrl" : "${formUrl}",
@ -116,15 +138,13 @@
"predicateUri" : "", "predicateUri" : "",
"objectClassUri" : "", "objectClassUri" : "",
"rangeDatatypeUri" : "${rangeDatatypeUriJson}", "rangeDatatypeUri" : "${rangeDatatypeUriJson}",
"rangeLang" : "", "rangeLang" : "${rangeLangJson}",
"assertions" : [ "${dataAssertion}" ] "assertions" : [ "${dataAssertion}" ]
} }
} }
} }
</c:set> </c:set>
<% <%
if( log.isDebugEnabled()) log.debug(request.getAttribute("editjson")); if( log.isDebugEnabled()) log.debug(request.getAttribute("editjson"));
@ -141,19 +161,20 @@
editConfig.prepareForDataPropUpdate(model,dps); editConfig.prepareForDataPropUpdate(model,dps);
} }
%> String propertyLabel = propertyName == "label" ? "name" : propertyName;
String actionText = dps == null ? "Add new " : "Edit ";
String submitLabel = actionText + propertyName;
String title = actionText + propertyName + " for " + subject.getName();
<c:set var="propertyLabel" value="${propertyName == 'label' ? 'name' : propertyName}" /> %>
<c:set var="submitLabel" value="Edit ${propertyLabel}" />
<c:set var="title" scope="request" value="Edit the ${propertyLabel} of ${subject.name}:" />
<jsp:include page="${preForm}"/> <jsp:include page="${preForm}"/>
<h2>${title}</h2> <h2><%= title %></h2>
<form action="<c:url value="/edit/processDatapropRdfForm.jsp"/>" > <form action="<c:url value="/edit/processDatapropRdfForm.jsp"/>" >
<v:input type="text" id="${propertyName}" size="30" /> <v:input type="text" id="${propertyName}" size="30" />
<input type="hidden" name="vitroNsProp" value="true" /> <input type="hidden" name="vitroNsProp" value="true" />
<p class="submit"><v:input type="submit" id="submit" value="${submitLabel}" cancel="${param.subjectUri}"/></p> <p class="submit"><v:input type="submit" id="submit" value="<%= submitLabel %>" cancel="${param.subjectUri}"/></p>
</form> </form>
<c:if test="${ (!empty param.datapropKey) && (empty param.deleteProhibited) }"> <c:if test="${ (!empty param.datapropKey) && (empty param.deleteProhibited) }">
@ -170,3 +191,4 @@
<jsp:include page="${postForm}"/> <jsp:include page="${postForm}"/>

View file

@ -380,7 +380,7 @@ and set a flag in the request to indicate "back button confusion"
int dpropHash = Integer.parseInt(editConfig.getDatapropKey()); int dpropHash = Integer.parseInt(editConfig.getDatapropKey());
String vitroNsProp = vreq.getParameter("vitroNsProp"); String vitroNsProp = vreq.getParameter("vitroNsProp");
boolean isVitroNsProp = vitroNsProp != null && vitroNsProp.equals("true"); boolean isVitroNsProp = vitroNsProp != null && vitroNsProp.equals("true");
DataPropertyStatement dps = RdfLiteralHash.getPropertyStmtByHash(subject, dpropHash, model, isVitroNsProp); DataPropertyStatement dps = RdfLiteralHash.getPropertyStmtByHash(subject, editConfig.getPredicateUri(), dpropHash, model, isVitroNsProp);
if (dps != null) if (dps != null)
return false; return false;

View file

@ -124,6 +124,7 @@ RY Description not working - FIX
<c:if test="${showEdits}"> <c:if test="${showEdits}">
<div id="dprop-vitro-moniker" class="propsItem editing" style="display:block;"> <div id="dprop-vitro-moniker" class="propsItem editing" style="display:block;">
<h3 class="propertyName">moniker</h3> <h3 class="propertyName">moniker</h3>
<c:if test="${showEdits}"><edLnk:editLinks item="<%= VitroVocabulary.MONIKER %>" icons="false"/></c:if>
<%-- Here's where we add the plus link, but only if there isn't already a moniker. --%> <%-- Here's where we add the plus link, but only if there isn't already a moniker. --%>
</c:if> </c:if>
<c:if test="${!empty entity.moniker}"> <c:if test="${!empty entity.moniker}">
@ -142,7 +143,7 @@ RY Description not working - FIX
<c:if test="${showEdits}"></div></c:if> <c:if test="${showEdits}"></div></c:if>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</div><!-- labelAndMoniker --> </div><!-- end labelAndMoniker -->
<c:if test="${ (!empty entity.anchor) || (!empty entity.linksList) }"> <c:if test="${ (!empty entity.anchor) || (!empty entity.linksList) }">
<div class="datatypePropertyValue"> <div class="datatypePropertyValue">
<div class="statementWrap"> <div class="statementWrap">