Skip to content

Commit 7378615

Browse files
authored
Merge pull request #12 from ndw/saxon12
Support Saxon 12
2 parents 11b1a15 + f51b074 commit 7378615

File tree

11 files changed

+174
-23
lines changed

11 files changed

+174
-23
lines changed

.github/workflows/build-pr.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@ jobs:
5252

5353
- name: Build
5454
run: |
55-
./gradlew dist
55+
./gradlew -PsaxonVersion=10.9 clean test
56+
./gradlew -PsaxonVersion=11.5 clean test
57+
./gradlew clean dist

.github/workflows/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ jobs:
4848

4949
- name: Build
5050
run: |
51-
./gradlew dist
51+
./gradlew -PsaxonVersion=10.9 clean test
52+
./gradlew -PsaxonVersion=11.5 clean test
53+
./gradlew clean dist
5254
5355
- name: Publish tagged release
5456
uses: softprops/action-gh-release@v1

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ buildConfig {
3535
buildConfigField('String', 'SAXON_VERSION', "\"${saxonVersion}\"")
3636
}
3737

38+
test {
39+
testLogging.showStandardStreams = true
40+
}
41+
3842
jar {
3943
archiveBaseName = "sinclude-${sincludeVersion}"
4044
manifest {

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ org.gradle.jvmargs=-Xmx4096m
22

33
basename=sinclude
44
sincludeTitle=Saxon XInclude
5-
sincludeVersion=5.0.0
5+
sincludeVersion=5.1.0
66

7-
saxonVersion=11.5
7+
saxonVersion=12.0

src/main/java/com/nwalsh/sinclude/XInclude.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.nwalsh.sinclude.schemes.SearchScheme;
1212
import com.nwalsh.sinclude.schemes.XPathScheme;
1313
import com.nwalsh.sinclude.schemes.XmlnsScheme;
14+
import com.nwalsh.sinclude.utils.NamespaceUtils;
1415
import com.nwalsh.sinclude.utils.NodeUtils;
1516
import com.nwalsh.sinclude.utils.ReceiverUtils;
1617
import com.nwalsh.sinclude.xpointer.DefaultFragmentIdParser;
@@ -76,23 +77,20 @@ public class XInclude {
7677
private static final Pattern charEqual = Pattern.compile("char\\s*=\\s*\\(.*\\)\\s*");
7778
private static final Pattern searchEqual = Pattern.compile("search\\s*=\\s*\\(.*\\)\\s*");
7879

79-
private static final FingerprintedQName fq_xml_id =
80-
new FingerprintedQName(xml_id.getPrefix(), xml_id.getNamespaceURI(), xml_id.getLocalName());
81-
private static final FingerprintedQName fq_xml_lang =
82-
new FingerprintedQName(xml_lang.getPrefix(), xml_lang.getNamespaceURI(), xml_lang.getLocalName());
83-
private static final FingerprintedQName fq_xml_base =
84-
new FingerprintedQName(xml_base.getPrefix(), xml_base.getNamespaceURI(), xml_base.getLocalName());
80+
private static final FingerprintedQName fq_xml_id = NamespaceUtils.fqName(xml_id);
81+
private static final FingerprintedQName fq_xml_lang = NamespaceUtils.fqName(xml_lang);
82+
private static final FingerprintedQName fq_xml_base = NamespaceUtils.fqName(xml_base);
8583

8684
private DebuggingLogger logger = null;
8785
private boolean trimText = false;
8886
private boolean fixupXmlBase = true;
8987
private boolean fixupXmlLang = true;
9088
private boolean copyAttributes = true; // XInclude 1.1
91-
private Vector<SchemeData> data = new Vector<>();
92-
private Vector<Scheme> schemes = new Vector<>();
89+
private final Vector<SchemeData> data = new Vector<>();
90+
private final Vector<Scheme> schemes = new Vector<>();
9391
private DocumentResolver resolver = null;
9492
private FragmentIdParser fragmentIdParser = null;
95-
private Stack<URI> uriStack = new Stack<>();
93+
private final Stack<URI> uriStack = new Stack<>();
9694

9795
public XInclude() {
9896
resolver = new DefaultDocumentResolver();
@@ -506,7 +504,7 @@ private XdmNode fixup(XdmNode xinclude, XdmNode document, String setId) {
506504
if (copy) {
507505
NodeName aname = ainfo.getNodeName();
508506
if (localAttrNS.equals(aname.getURI())) {
509-
aname = new FingerprintedQName("", "", aname.getLocalPart());
507+
aname = NamespaceUtils.fqName("", "", aname.getLocalPart());
510508
}
511509

512510
copied.add(aname);
@@ -547,7 +545,7 @@ private XdmNode fixup(XdmNode xinclude, XdmNode document, String setId) {
547545
}
548546

549547
NodeInfo ni = node.getUnderlyingNode();
550-
FingerprintedQName name = new FingerprintedQName(ni.getPrefix(), ni.getURI(), ni.getLocalPart());
548+
FingerprintedQName name = NamespaceUtils.fqName(ni.getPrefix(), ni.getURI(), ni.getLocalPart());
551549
receiver.startElement(name, ni.getSchemaType(), amap, ni.getAllNamespaces(), ni.saveLocation(), 0);
552550
XdmSequenceIterator<XdmNode> citer = node.axisIterator(Axis.CHILD);
553551
while (citer.hasNext()) {
@@ -645,11 +643,11 @@ private void traverse(Receiver receiver, XdmNode node) throws XPathException {
645643
receiver.append(handlers.get(node.getNodeName()).process(node).getUnderlyingNode());
646644
} else {
647645
NodeInfo inode = node.getUnderlyingNode();
648-
FingerprintedQName name = new FingerprintedQName(inode.getPrefix(), inode.getURI(), inode.getLocalPart());
646+
FingerprintedQName name = NamespaceUtils.fqName(inode.getPrefix(), inode.getURI(), inode.getLocalPart());
649647

650648
final AttributeMap amap;
651649
if (root && fixupXmlBase && overrideBaseURI != null && inode.getAttributeValue(NS_XML, "base") == null) {
652-
FingerprintedQName xml_base = new FingerprintedQName("xml", NS_XML, "base");
650+
FingerprintedQName xml_base = NamespaceUtils.fqName("xml", NS_XML, "base");
653651
AttributeInfo base = new AttributeInfo(xml_base, BuiltInAtomicType.ANY_URI, overrideBaseURI.toString(), inode.saveLocation(), 0);
654652
amap = inode.attributes().put(base);
655653
} else {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.nwalsh.sinclude.exceptions;
2+
3+
public class XIncludeObjectModelException extends UnsupportedOperationException {
4+
public XIncludeObjectModelException(String message) {
5+
super(message);
6+
}
7+
public XIncludeObjectModelException(Throwable cause) {
8+
super(cause);
9+
}
10+
public XIncludeObjectModelException(String message, Throwable cause) {
11+
super(message, cause);
12+
}
13+
}

src/main/java/com/nwalsh/sinclude/schemes/AbstractXmlScheme.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.nwalsh.sinclude.XInclude;
44
import com.nwalsh.sinclude.exceptions.FixupException;
5+
import com.nwalsh.sinclude.utils.NamespaceUtils;
56
import com.nwalsh.sinclude.utils.NodeUtils;
67
import com.nwalsh.sinclude.utils.ReceiverUtils;
78
import net.sf.saxon.event.Receiver;
@@ -24,9 +25,9 @@
2425

2526
public abstract class AbstractXmlScheme {
2627
private static final FingerprintedQName fq_xml_lang =
27-
new FingerprintedQName(xml_lang.getPrefix(), xml_lang.getNamespaceURI(), xml_lang.getLocalName());
28+
NamespaceUtils.fqName(xml_lang.getPrefix(), xml_lang.getNamespaceURI(), xml_lang.getLocalName());
2829
private static final FingerprintedQName fq_xml_base =
29-
new FingerprintedQName(xml_base.getPrefix(), xml_base.getNamespaceURI(), xml_base.getLocalName());
30+
NamespaceUtils.fqName(xml_base.getPrefix(), xml_base.getNamespaceURI(), xml_base.getLocalName());
3031

3132
protected XInclude xinclude = null;
3233
protected String contextLanguage = null;
@@ -76,7 +77,7 @@ protected XdmNode fixup(XdmNode node) {
7677
}
7778

7879
NodeInfo ni = node.getUnderlyingNode();
79-
FingerprintedQName name = new FingerprintedQName(ni.getPrefix(), ni.getURI(), ni.getLocalPart());
80+
FingerprintedQName name = NamespaceUtils.fqName(ni.getPrefix(), ni.getURI(), ni.getLocalPart());
8081
receiver.startElement(name, ni.getSchemaType(), attributes, ni.getAllNamespaces(), ni.saveLocation(), 0);
8182
XdmSequenceIterator<XdmNode> citer = node.axisIterator(Axis.CHILD);
8283
while (citer.hasNext()) {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.nwalsh.sinclude.utils;
2+
3+
import com.nwalsh.sinclude.exceptions.XIncludeObjectModelException;
4+
import net.sf.saxon.om.FingerprintedQName;
5+
import net.sf.saxon.s9api.QName;
6+
import net.sf.saxon.value.QNameValue;
7+
8+
import java.lang.reflect.Constructor;
9+
import java.lang.reflect.InvocationTargetException;
10+
import java.lang.reflect.Method;
11+
12+
// This class uses reflection to handle construction of QNames and FingerprintedQNames in a way
13+
// that's compatible with Saxon 10, 11, or 12
14+
15+
public class NamespaceUtils {
16+
public static FingerprintedQName fqName(QName qname) {
17+
Method getns;
18+
try {
19+
// Saxon 12
20+
getns = QName.class.getMethod("getNamespace");
21+
Object ns = getns.invoke(qname);
22+
return fqName(qname.getPrefix(), (String) ns, qname.getLocalName());
23+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException err1) {
24+
try {
25+
// Saxon 10 or 11
26+
getns = QName.class.getMethod("getNamespaceURI");
27+
Object ns = getns.invoke(qname);
28+
return fqName(qname.getPrefix(), (String) ns, qname.getLocalName());
29+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException err2) {
30+
throw new XIncludeObjectModelException("Failed to instantiate QName", err2);
31+
}
32+
}
33+
}
34+
35+
public static FingerprintedQName fqName(String prefix, String nsuri, String localName) {
36+
Constructor<?> fqcon;
37+
try {
38+
// Saxon 12
39+
Class<?> uriClass = Class.forName("net.sf.saxon.om.NamespaceUri");
40+
fqcon = FingerprintedQName.class.getConstructor(String.class, uriClass, String.class);
41+
Method uriOf = uriClass.getMethod("of", String.class);
42+
Object uri = uriOf.invoke(null, nsuri);
43+
return (FingerprintedQName) fqcon.newInstance(prefix, (Object) uri, localName);
44+
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException err1) {
45+
try {
46+
// Saxon 10 or 11
47+
fqcon = FingerprintedQName.class.getConstructor(String.class, String.class, String.class);
48+
return (FingerprintedQName) fqcon.newInstance(prefix, nsuri, localName);
49+
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException err2) {
50+
throw new XIncludeObjectModelException("Failed to instantiate FingerprintedQName", err2);
51+
}
52+
}
53+
}
54+
55+
public static QName qName(QNameValue qname) {
56+
String nsString;
57+
Object ns = qname.getNamespaceURI();
58+
nsString = (ns instanceof String) ? (String) ns : ns.toString();
59+
return new QName(qname.getPrefix(), nsString, qname.getLocalName());
60+
}
61+
}

src/main/java/com/nwalsh/xslt/XIncludeFunction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.nwalsh.DebuggingLogger;
44
import com.nwalsh.sinclude.XInclude;
5+
import com.nwalsh.sinclude.utils.NamespaceUtils;
56
import net.sf.saxon.expr.XPathContext;
67
import net.sf.saxon.lib.ExtensionFunctionCall;
78
import net.sf.saxon.lib.ExtensionFunctionDefinition;
@@ -129,8 +130,7 @@ private HashMap<QName,String> parseMap(MapItem item) throws XPathException {
129130
while (next != null) {
130131
final QName key;
131132
if (next.getItemType() == BuiltInAtomicType.QNAME) {
132-
QNameValue qkey = (QNameValue) next;
133-
key = new QName(qkey.getPrefix(), qkey.getNamespaceURI(), qkey.getLocalName());
133+
key = NamespaceUtils.qName((QNameValue) next);
134134
} else {
135135
throw new IllegalArgumentException("Option map keys must be QNames");
136136
}

src/test/java/com/nwalsh/sinclude/FragIdParseTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.nwalsh.sinclude.exceptions.UnknownXPointerSchemeException;
44
import com.nwalsh.sinclude.exceptions.XIncludeSyntaxException;
5-
import com.nwalsh.sinclude.xpointer.DefaultFragmentIdParser;
65
import com.nwalsh.sinclude.xpointer.FragmentIdParser;
76
import com.nwalsh.sinclude.xpointer.ParseType;
87
import com.nwalsh.sinclude.xpointer.Scheme;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.nwalsh.sinclude;
2+
3+
import com.nwalsh.sinclude.utils.NamespaceUtils;
4+
import net.sf.saxon.om.FingerprintedQName;
5+
import net.sf.saxon.s9api.Processor;
6+
import net.sf.saxon.s9api.QName;
7+
import net.sf.saxon.value.QNameValue;
8+
import org.junit.Assert;
9+
import org.junit.Before;
10+
import org.junit.Test;
11+
12+
import java.lang.reflect.Constructor;
13+
import java.lang.reflect.InvocationTargetException;
14+
import java.lang.reflect.Method;
15+
16+
public class NamespaceUtilsTest {
17+
static String version = null;
18+
19+
@Before
20+
public void setUp() {
21+
if (version == null) {
22+
version = new Processor(false).getSaxonProductVersion();
23+
System.out.println("Running with Saxon version " + version);
24+
}
25+
}
26+
27+
@Test
28+
public void fqNameFromParts() {
29+
FingerprintedQName fqname = NamespaceUtils.fqName("ex", "http://example.com/", "local");
30+
Assert.assertNotNull(fqname);
31+
}
32+
33+
@Test
34+
public void fqNameFromQName() {
35+
QName qname = new QName("ex", "http://example.com/", "local");
36+
FingerprintedQName fqname = NamespaceUtils.fqName(qname);
37+
Assert.assertNotNull(fqname);
38+
Assert.assertEquals("ex", fqname.getPrefix());
39+
Assert.assertEquals("local", fqname.getLocalPart());
40+
}
41+
42+
@Test
43+
public void qnameFromQNameValue() {
44+
// Sigh, we need reflection to test reflection...
45+
Constructor<?> qvcon;
46+
QNameValue value = null;
47+
try {
48+
// Saxon 12
49+
Class<?> uriClass = Class.forName("net.sf.saxon.om.NamespaceUri");
50+
qvcon = QNameValue.class.getConstructor(String.class, uriClass, String.class);
51+
Method uriOf = uriClass.getMethod("of", String.class);
52+
Object uri = uriOf.invoke(null, "http://example.com/");
53+
value = (QNameValue) qvcon.newInstance("ex", (Object) uri, "local");
54+
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException |
55+
InvocationTargetException err1) {
56+
try {
57+
// Saxon 10 or 11
58+
qvcon = QNameValue.class.getConstructor(String.class, String.class, String.class);
59+
value = (QNameValue) qvcon.newInstance("ex", "http://example.com/", "local");
60+
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException err2) {
61+
Assert.fail();
62+
}
63+
}
64+
65+
QName qname = NamespaceUtils.qName(value);
66+
Assert.assertNotNull(qname);
67+
Assert.assertEquals("ex", qname.getPrefix());
68+
Assert.assertEquals("local", qname.getLocalName());
69+
}
70+
71+
}

0 commit comments

Comments
 (0)