blob: e67c39f55c1cdcecfcf1ad7327236cbf56a2b14c [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed 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 org.apache.xmlbeans.impl.values;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.common.PrefixResolver;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.common.ValidationContext;
import org.apache.xmlbeans.impl.common.XMLChar;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class XmlListImpl extends XmlObjectBase implements XmlAnySimpleType {
public XmlListImpl(SchemaType type, boolean complex) {
_schemaType = type;
initComplexType(complex, false);
}
public SchemaType schemaType() {
return _schemaType;
}
private final SchemaType _schemaType;
private XmlSimpleList _value;
private XmlSimpleList _jvalue;
// SIMPLE VALUE ACCESSORS BELOW -------------------------------------------
// gets raw text value
private static String compute_list_text(List<Object> xList) {
return xList.isEmpty() ? "" : xList.stream().map(XmlListImpl::object2String).collect(Collectors.joining(" "));
}
private static String object2String(Object o) {
String s = (o instanceof SimpleValue) ? ((SimpleValue) o).getStringValue() : o.toString();
return (s == null) ? "" : s;
}
protected String compute_text(NamespaceManager nsm) {
return compute_list_text(_value);
}
protected boolean is_defaultable_ws(String v) {
try {
XmlSimpleList savedValue = _value;
set_text(v);
// restore the saved value
_value = savedValue;
return false;
} catch (XmlValueOutOfRangeException e) {
return true;
}
}
protected void set_text(String s) {
// first check against any patterns...
if (_validateOnSet() && !_schemaType.matchPatternFacet(s)) {
throw new XmlValueOutOfRangeException(XmlErrorCodes.DATATYPE_VALID$PATTERN_VALID,
new Object[]{"list", s, QNameHelper.readable(_schemaType)});
}
SchemaType itemType = _schemaType.getListItemType();
XmlSimpleList newval = lex(s, itemType, _voorVc, has_store() ? get_store() : null);
// check enumeration
if (_validateOnSet()) {
validateValue(newval, _schemaType, _voorVc);
}
// we made it all the way through; so we're OK.
_value = newval;
_jvalue = null;
}
private static final String[] EMPTY_STRINGARRAY = new String[0];
public static String[] split_list(String s) {
if (s.length() == 0) {
return EMPTY_STRINGARRAY;
}
List<String> result = new ArrayList<>();
int i = 0;
int start;
for (; ; ) {
while (i < s.length() && XMLChar.isSpace(s.charAt(i))) {
i += 1;
}
if (i >= s.length()) {
return result.toArray(EMPTY_STRINGARRAY);
}
start = i;
while (i < s.length() && !XMLChar.isSpace(s.charAt(i))) {
i += 1;
}
result.add(s.substring(start, i));
}
}
public static XmlSimpleList lex(String s, SchemaType itemType, ValidationContext ctx, PrefixResolver resolver) {
String[] parts = split_list(s);
Function<String, XmlAnySimpleType> fun = (str) -> {
try {
return itemType.newValue(str);
} catch (XmlValueOutOfRangeException e) {
Object[] obj = {"item '" + str + "' is not a valid value of " + QNameHelper.readable(itemType)};
ctx.invalid(XmlErrorCodes.LIST, obj);
return null;
}
};
boolean pushed = false;
if (resolver != null) {
NamespaceContext.push(new NamespaceContext(resolver));
pushed = true;
}
try {
List<? super Object> list = Stream.of(parts).map(fun).collect(Collectors.toList());
return new XmlSimpleList(list);
} finally {
if (pushed) {
NamespaceContext.pop();
}
}
}
protected void set_nil() {
_value = null;
}
public List<?> xgetListValue() {
check_dated();
return _value;
}
public List<?> getListValue() {
check_dated();
if (_value == null) {
return null;
}
if (_jvalue != null) {
return _jvalue;
}
List<Object> javaResult = new ArrayList<>();
for (Object o : _value) {
javaResult.add(java_value((XmlObject) o));
}
_jvalue = new XmlSimpleList(javaResult);
return _jvalue;
}
private static boolean permits_inner_space(XmlObject obj) {
switch (((SimpleValue) obj).instanceType().getPrimitiveType().getBuiltinTypeCode()) {
case SchemaType.BTC_STRING:
case SchemaType.BTC_ANY_URI:
case SchemaType.BTC_ANY_SIMPLE:
case SchemaType.BTC_ANY_TYPE:
return true;
default:
return false;
}
}
private static boolean contains_white_space(String s) {
return s.indexOf(' ') >= 0 ||
s.indexOf('\t') >= 0 ||
s.indexOf('\n') >= 0 ||
s.indexOf('\r') >= 0;
}
public void set_list(List<?> list) {
SchemaType itemType = _schemaType.getListItemType();
XmlSimpleList xList;
boolean pushed = false;
if (has_store()) {
NamespaceContext.push(new NamespaceContext(get_store()));
pushed = true;
}
Function<Object, XmlAnySimpleType> fun = (entry) -> {
if ((entry instanceof XmlObject) && permits_inner_space((XmlObject) entry)) {
String stringrep = entry.toString();
if (contains_white_space(stringrep)) {
throw new XmlValueOutOfRangeException();
}
}
return itemType.newValue(entry);
};
try {
List<? super Object> l = list.stream().map(fun).collect(Collectors.toList());
xList = new XmlSimpleList(l);
} finally {
if (pushed) {
NamespaceContext.pop();
}
}
if (_validateOnSet()) {
// check enumeration + min/max/etc
validateValue(xList, _schemaType, _voorVc);
}
_value = xList;
_jvalue = null;
}
public static void validateValue(XmlSimpleList items, SchemaType sType, ValidationContext context) {
XmlObject[] enumvals = sType.getEnumerationValues();
checkEnum:
if (enumvals != null) {
for (XmlObject enumval : enumvals) {
if (equal_xmlLists(items, ((XmlObjectBase) enumval).xgetListValue())) {
break checkEnum;
}
}
context.invalid(XmlErrorCodes.DATATYPE_ENUM_VALID,
new Object[]{"list", items, QNameHelper.readable(sType)});
}
XmlObject o;
int i;
if ((o = sType.getFacet(SchemaType.FACET_LENGTH)) != null) {
if ((i = ((SimpleValue) o).getIntValue()) != items.size()) {
context.invalid(XmlErrorCodes.DATATYPE_LENGTH_VALID$LIST_LENGTH,
new Object[]{items, items.size(), i, QNameHelper.readable(sType)});
}
}
if ((o = sType.getFacet(SchemaType.FACET_MIN_LENGTH)) != null) {
if ((i = ((SimpleValue) o).getIntValue()) > items.size()) {
context.invalid(XmlErrorCodes.DATATYPE_MIN_LENGTH_VALID$LIST_LENGTH,
new Object[]{items, items.size(), i, QNameHelper.readable(sType)});
}
}
if ((o = sType.getFacet(SchemaType.FACET_MAX_LENGTH)) != null) {
if ((i = ((SimpleValue) o).getIntValue()) < items.size()) {
context.invalid(XmlErrorCodes.DATATYPE_MAX_LENGTH_VALID$LIST_LENGTH,
new Object[]{items, items.size(), i, QNameHelper.readable(sType)});
}
}
}
// comparators
// protected int compare_to(XmlObject i) - no sorting order; inherit from base
protected boolean equal_to(XmlObject obj) {
return equal_xmlLists(_value, ((XmlObjectBase) obj).xgetListValue());
}
private static boolean equal_xmlLists(List<?> a, List<?> b) {
if (a.size() != b.size()) {
return false;
}
for (int i = 0; i < a.size(); i++) {
if (!a.get(i).equals(b.get(i))) {
return false;
}
}
return true;
}
protected int value_hash_code() {
if (_value == null) {
return 0;
}
// hash code probes 9 distributed values, plus the last
int hash = _value.size();
int incr = _value.size() / 9;
if (incr < 1) {
incr = 1;
}
int i;
for (i = 0; i < _value.size(); i += incr) {
hash *= 19;
hash += _value.get(i).hashCode();
}
if (i < _value.size()) {
hash *= 19;
hash += _value.get(i).hashCode();
}
return hash;
}
protected void validate_simpleval(String lexical, ValidationContext ctx) {
validateValue((XmlSimpleList) xgetListValue(), schemaType(), ctx);
}
}