diff --git a/src/main/java/gr/forth/ics/isl/x3ml/X3MLEngine.java b/src/main/java/gr/forth/ics/isl/x3ml/X3MLEngine.java index 3644d44..3eb5f23 100644 --- a/src/main/java/gr/forth/ics/isl/x3ml/X3MLEngine.java +++ b/src/main/java/gr/forth/ics/isl/x3ml/X3MLEngine.java @@ -52,6 +52,7 @@ Licensed to the Apache Software Foundation (ASF) under one import static gr.forth.ics.isl.x3ml.engine.X3ML.MappingNamespace; import static gr.forth.ics.isl.x3ml.engine.X3ML.RootElement; import gr.forth.ics.isl.x3ml.engine.X3ML.TargetInfo; +import gr.forth.ics.isl.x3ml.engine.xpath.Namespace; import gr.forth.Labels; import gr.forth.Utils; import gr.forth.ics.isl.x3ml.engine.ModelOutput; @@ -311,6 +312,7 @@ private void addDefaultNamespaces(){ ((XPathContext) namespaceContext).addNamespace(Labels.XML, Labels.XML_NAMESPACE); prefixes.add(Labels.XML); ((XPathContext) namespaceContext).addNamespace(Labels.SKOS, Labels.SKOS_NAMESPACE); + ((XPathContext) namespaceContext).addNamespace(Namespace.CUSTOM_FUNCTIONS_PREFIX, Namespace.CUSTOM_FUNCTIONS_NAMESPACE); prefixes.add(Labels.SKOS); } diff --git a/src/main/java/gr/forth/ics/isl/x3ml/engine/XPathInput.java b/src/main/java/gr/forth/ics/isl/x3ml/engine/XPathInput.java index a046d5c..9372583 100644 --- a/src/main/java/gr/forth/ics/isl/x3ml/engine/XPathInput.java +++ b/src/main/java/gr/forth/ics/isl/x3ml/engine/XPathInput.java @@ -39,6 +39,10 @@ Licensed to the Apache Software Foundation (ASF) under one import gr.forth.IterableNodeList; import gr.forth.Labels; import gr.forth.Utils; +import gr.forth.ics.isl.x3ml.engine.X3ML.GeneratorElement; +import gr.forth.ics.isl.x3ml.engine.X3ML.SourceType; +import gr.forth.ics.isl.x3ml.engine.xpath.UUIDFunction_v3; + import java.io.StringWriter; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; @@ -49,6 +53,7 @@ Licensed to the Apache Software Foundation (ASF) under one import javax.xml.transform.stream.StreamResult; import static gr.forth.ics.isl.x3ml.X3MLEngine.exception; import lombok.extern.log4j.Log4j2; +import net.sf.saxon.Configuration; import net.sf.saxon.dom.DOMNodeList; import static org.joox.JOOX.$; @@ -63,9 +68,8 @@ Licensed to the Apache Software Foundation (ASF) under one * @author Yannis Marketakis <marketak@ics.forth.gr> */ @Log4j2 -public class XPathInput { - - private final XPathFactory pathFactory = new net.sf.saxon.xpath.XPathFactoryImpl(); +public class XPathInput { + private final XPathFactory pathFactory; private final NamespaceContext namespaceContext; private final String languageFromMapping; private final Node rootNode; @@ -78,6 +82,12 @@ public XPathInput(Node rootNode, NamespaceContext namespaceContext, String langu this.rootNode = rootNode; this.namespaceContext = namespaceContext; this.languageFromMapping = languageFromMapping; + + // register custom xpath functions + net.sf.saxon.xpath.XPathFactoryImpl pathFactoryImpl = new net.sf.saxon.xpath.XPathFactoryImpl(); + Configuration config = pathFactoryImpl.getConfiguration(); + config.registerExtensionFunction(new UUIDFunction_v3()); + this.pathFactory = pathFactoryImpl; } public X3ML.ArgValue evaluateArgument(Node node, int index, GeneratorElement generatorElement, String argName, SourceType defaultType, boolean mergeMultipleValues) { diff --git a/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/Namespace.java b/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/Namespace.java new file mode 100644 index 0000000..e02d2db --- /dev/null +++ b/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/Namespace.java @@ -0,0 +1,6 @@ +package gr.forth.ics.isl.x3ml.engine.xpath; + +public class Namespace { + public static String CUSTOM_FUNCTIONS_PREFIX = "x3ml"; + public static String CUSTOM_FUNCTIONS_NAMESPACE = "http://gr.forth.ics.isl/x3ml/custom-functions"; +} diff --git a/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/UUIDFunction_v3.java b/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/UUIDFunction_v3.java new file mode 100644 index 0000000..5ca531e --- /dev/null +++ b/src/main/java/gr/forth/ics/isl/x3ml/engine/xpath/UUIDFunction_v3.java @@ -0,0 +1,59 @@ +/*============================================================================== +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +==============================================================================*/ +package gr.forth.ics.isl.x3ml.engine.xpath; + +import java.util.UUID; + +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.lib.ExtensionFunctionDefinition; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.StringValue; + +public class UUIDFunction_v3 extends ExtensionFunctionDefinition { + private static String FUNCTION_NAME = "uuid"; + + @Override + public StructuredQName getFunctionQName() { + return new StructuredQName(Namespace.CUSTOM_FUNCTIONS_PREFIX, Namespace.CUSTOM_FUNCTIONS_NAMESPACE, FUNCTION_NAME); + } + + @Override + public SequenceType[] getArgumentTypes() { + return new SequenceType[]{SequenceType.SINGLE_STRING}; + } + + @Override + public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { + return SequenceType.SINGLE_STRING; + } + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { + String input = arguments[0].head().getStringValue(); + String uuid = UUID.nameUUIDFromBytes(input.getBytes()).toString().toUpperCase(); + return StringValue.makeStringValue(uuid); + } + }; + } +} diff --git a/src/test/java/eu/delving/x3ml/TestCustomXpathFunctions.java b/src/test/java/eu/delving/x3ml/TestCustomXpathFunctions.java new file mode 100644 index 0000000..aedf373 --- /dev/null +++ b/src/test/java/eu/delving/x3ml/TestCustomXpathFunctions.java @@ -0,0 +1,44 @@ +/*============================================================================== +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +==============================================================================*/ +package eu.delving.x3ml; + +import static eu.delving.x3ml.AllTests.*; +import static org.junit.Assert.assertTrue; + + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +import gr.forth.ics.isl.x3ml.X3MLEngine; + +public class TestCustomXpathFunctions { + + @Test + public void testUUIDv3Function() { + X3MLEngine engine = engine("/custom_functions/01-coin-simple.x3ml"); + X3MLEngine.Output output = engine.execute(document("/custom_functions/01-coin-input.xml"), policy("/custom_functions/00-generator-policy.xml")); + String[] mappingResult = output.toStringArray(); + System.out.println(StringUtils.join(mappingResult, "\n")); + String[] expectedResult = xmlToNTriples("/custom_functions/01-coin-simple-rdf.xml"); + List diff = compareNTriples(expectedResult, mappingResult); + assertTrue("\n" + StringUtils.join(diff, "\n") + "\n", errorFree(diff)); + } +} diff --git a/src/test/resources/custom_functions/00-generator-policy.xml b/src/test/resources/custom_functions/00-generator-policy.xml new file mode 100644 index 0000000..3a89eb8 --- /dev/null +++ b/src/test/resources/custom_functions/00-generator-policy.xml @@ -0,0 +1,27 @@ + + + + + {label} + + + {hierarchy}/{term} + + + + + + + + + + {term} + + + + + + + + + diff --git a/src/test/resources/custom_functions/01-coin-input.xml b/src/test/resources/custom_functions/01-coin-input.xml new file mode 100644 index 0000000..584d030 --- /dev/null +++ b/src/test/resources/custom_functions/01-coin-input.xml @@ -0,0 +1,114 @@ + + + + 627 + 1 + 242 + 2 + 1980er Jahre + 566 + 536 + 30 + 244 + mint mark + 99 + 0 + -116 + -115 + 1088408850 + 3.46 + 4 + 1 + CN.DOMI + Iuppiter in Quadriga n. r. .. + - + 000627 + 116 - 115 v. Chr. + + + + 1 + Österreich + Austria + + + 2 + Deutchland + Germany + + + 242 + Mautern + 10 + 000020_000030_000090_000170_000010 + 0 + + + 666 + To Be Avoided + 10 + 9494949494949 + 0 + + + 2 + Streufund + stray-find + + + 566 + REPUBLIK + ROME / REPUBLIC + 30 + 000030 + + + 536 + CN.DOMI, Q. CVRTI, M. SILA + CN. DOMI, Q. CVRTI, M. SILA + 940 + 000030_000940 + 0 + + + 30 + D + D + 140 + 000010_000020_000140 + 2 + 0 + + + 244 + Rom (Rep.) + Rome + 10 + 000030_000010 + 0 + + diff --git a/src/test/resources/custom_functions/01-coin-simple-rdf.xml b/src/test/resources/custom_functions/01-coin-simple-rdf.xml new file mode 100644 index 0000000..d5ba672 --- /dev/null +++ b/src/test/resources/custom_functions/01-coin-simple-rdf.xml @@ -0,0 +1,13 @@ + + + + + + 627 + + + + \ No newline at end of file diff --git a/src/test/resources/custom_functions/01-coin-simple.x3ml b/src/test/resources/custom_functions/01-coin-simple.x3ml new file mode 100644 index 0000000..2f3f04c --- /dev/null +++ b/src/test/resources/custom_functions/01-coin-simple.x3ml @@ -0,0 +1,45 @@ + + + + + + + + + + + + //COIN + + + crm:E22_Man-Made_Object + + + + + + + ID + + crm:P1_is_identified_by + + + + ID + + + crm:E41_Appellation + + x3ml:uuid(text()) + + + text() + + + + + + + + + \ No newline at end of file