1
2
3
4
5
6 package dev.metaschema.core.metapath.function.library;
7
8 import java.util.List;
9
10 import dev.metaschema.core.metapath.DynamicContext;
11 import dev.metaschema.core.metapath.MetapathConstants;
12 import dev.metaschema.core.metapath.function.FunctionUtils;
13 import dev.metaschema.core.metapath.function.IArgument;
14 import dev.metaschema.core.metapath.function.IFunction;
15 import dev.metaschema.core.metapath.function.InvalidArgumentFunctionException;
16 import dev.metaschema.core.metapath.function.UriFunctionException;
17 import dev.metaschema.core.metapath.item.IItem;
18 import dev.metaschema.core.metapath.item.ISequence;
19 import dev.metaschema.core.metapath.item.atomic.IAnyUriItem;
20 import dev.metaschema.core.metapath.item.atomic.IStringItem;
21 import dev.metaschema.core.util.ObjectUtils;
22 import edu.umd.cs.findbugs.annotations.NonNull;
23 import edu.umd.cs.findbugs.annotations.Nullable;
24
25
26
27
28
29
30 public final class FnResolveUri {
31 private static final String NAME = "resolve-uri";
32 @NonNull
33 static final IFunction SIGNATURE_ONE_ARG = IFunction.builder()
34 .name(NAME)
35 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
36 .deterministic()
37 .contextDependent()
38 .focusIndependent()
39 .argument(IArgument.builder()
40 .name("relative")
41 .type(IStringItem.type())
42 .zeroOrOne()
43 .build())
44 .returnType(IAnyUriItem.type())
45 .returnZeroOrOne()
46 .functionHandler(FnResolveUri::executeOneArg)
47 .build();
48
49 @NonNull
50 static final IFunction SIGNATURE_TWO_ARG = IFunction.builder()
51 .name(NAME)
52 .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS)
53 .deterministic()
54 .contextIndependent()
55 .focusIndependent()
56 .argument(IArgument.builder()
57 .name("relative")
58 .type(IStringItem.type())
59 .zeroOrOne()
60 .build())
61 .argument(IArgument.builder()
62 .name("base")
63 .type(IStringItem.type())
64 .one()
65 .build())
66 .returnType(IAnyUriItem.type())
67 .returnZeroOrOne()
68 .functionHandler(FnResolveUri::executeTwoArg)
69 .build();
70
71 private FnResolveUri() {
72
73 }
74
75 @SuppressWarnings("unused")
76 @NonNull
77 private static ISequence<IAnyUriItem> executeOneArg(
78 @NonNull IFunction function,
79 @NonNull List<ISequence<?>> arguments,
80 @NonNull DynamicContext dynamicContext,
81 IItem focus) {
82
83 ISequence<? extends IStringItem> relativeSequence
84 = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0)));
85 if (relativeSequence.isEmpty()) {
86 return ISequence.empty();
87 }
88
89 IStringItem relativeString = relativeSequence.getFirstItem(true);
90 IAnyUriItem resolvedUri = null;
91 if (relativeString != null) {
92 resolvedUri = fnResolveUri(relativeString, null, dynamicContext);
93 }
94 return ISequence.of(resolvedUri);
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 @NonNull
113 private static ISequence<IAnyUriItem> executeTwoArg(
114 @NonNull IFunction function,
115 @NonNull List<ISequence<?>> arguments,
116 @NonNull DynamicContext dynamicContext,
117 IItem focus) {
118
119
120 assert arguments.size() == 2;
121
122 ISequence<? extends IStringItem> relativeSequence = FunctionUtils.asType(
123 ObjectUtils.requireNonNull(arguments.get(0)));
124 if (relativeSequence.isEmpty()) {
125 return ISequence.empty();
126 }
127
128 ISequence<? extends IStringItem> baseSequence = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1)));
129 IStringItem baseString = baseSequence.getFirstItem(true);
130
131 if (baseString == null) {
132 throw new InvalidArgumentFunctionException(
133 InvalidArgumentFunctionException.INVALID_ARGUMENT_TO_RESOLVE_URI,
134 "Invalid argument to fn:resolve-uri().");
135 }
136 IAnyUriItem baseUri = IAnyUriItem.cast(baseString);
137
138 IStringItem relativeString = relativeSequence.getFirstItem(true);
139
140 IAnyUriItem resolvedUri = null;
141 if (relativeString != null) {
142 resolvedUri = fnResolveUri(relativeString, baseUri, dynamicContext);
143 }
144 return ISequence.of(resolvedUri);
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158
159 @Nullable
160 public static IAnyUriItem fnResolveUri(
161 @NonNull IStringItem relative,
162 @Nullable IAnyUriItem base,
163 @NonNull DynamicContext dynamicContext) {
164 return fnResolveUri(IAnyUriItem.cast(relative), base, dynamicContext);
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 @NonNull
182 public static IAnyUriItem fnResolveUri(
183 @NonNull IAnyUriItem relative,
184 @Nullable IAnyUriItem base,
185 @NonNull DynamicContext dynamicContext) {
186
187 IAnyUriItem baseUri = base;
188 if (baseUri == null) {
189 baseUri = FnStaticBaseUri.fnStaticBaseUri(dynamicContext);
190 if (baseUri == null) {
191 throw new UriFunctionException(UriFunctionException.BASE_URI_NOT_DEFINED_IN_STATIC_CONTEXT,
192 "The base-uri is not defined in the static context");
193 }
194 }
195
196 return baseUri.resolve(relative);
197 }
198 }