diff --git a/docs/dsp-tools-excel2xml.md b/docs/dsp-tools-excel2xml.md
index e848f4f20..790da569f 100644
--- a/docs/dsp-tools-excel2xml.md
+++ b/docs/dsp-tools-excel2xml.md
@@ -229,6 +229,23 @@ else:
excel2xml.make_boolean_prop(":hasBoolean", False)
```
+#### Supported text values
+DSP's only restriction on text-properties is that the string must be longer than 0. It is, for example, possible to
+upload the following property:
+```xml
+
+
+ -
+
+```
+
+`excel2xml` allows to create such a property, but text values that don't meet the requirements of
+[`excel2xml.check_notna()`](#check-if-a-cell-contains-a-usable-value) will trigger a warning, for example:
+```python
+excel2xml.make_text_prop(":hasText", " ") # OK, but triggers a warning
+excel2xml.make_text_prop(":hasText", "-") # OK, but triggers a warning
+```
+
### 8. Append the resource to root
At the end of the for-loop, it is important not to forget to append the finished resource to the root.
@@ -245,11 +262,28 @@ usable if it is
- a number (integer or float, but not numpy.nan)
- a boolean
- - a string with at least one Unicode letter (matching the regex `\p{L}`), underscore, ?, !, or number, but not "None",
- "", "N/A", or "-"
+ - a string with at least one Unicode letter (matching the regex ``\\p{L}``) or number, or at least one _, !, or ?
+ (The strings "None", "", "N/A", and "-" are considered invalid.)
- a PropertyElement whose "value" fulfills the above criteria
-Why not just checking a cell by its boolean value? Like:
+Examples:
+```
+check_notna(0) == True
+check_notna(False) == True
+check_notna("œ") == True
+check_notna("0") == True
+check_notna("_") == True
+check_notna("!") == True
+check_notna("?") == True
+check_notna(None) == False
+check_notna("None") == False
+check_notna() == False
+check_notna("") == False
+check_notna("-") == False
+check_notna(" ") == False
+```
+
+But why not just checking a cell by its boolean value? Like:
```
if cell:
resource.append(make_*_prop(cell))
@@ -264,7 +298,7 @@ might expect:
| " " | True | False, because an empty string is not usable for a text property |
| numpy.nan | True | False, because N/A is not a usable value |
| pandas.NA | TypeError (*) | False, because N/A is not a usable value |
-| "" | True | False, because this is the string representation of N/A |
+| "<NA>" | True | False, because this is the string representation of N/A |
| "-" | True | False, because this is a placeholder in an empty text field |
(*) TypeError: boolean value of NA is ambiguous
diff --git a/knora/dsplib/utils/shared.py b/knora/dsplib/utils/shared.py
index 6d20c0095..ec5692a5a 100644
--- a/knora/dsplib/utils/shared.py
+++ b/knora/dsplib/utils/shared.py
@@ -175,8 +175,8 @@ def check_notna(value: Optional[Any]) -> bool:
Check a value if it is usable in the context of data archiving. A value is considered usable if it is
- a number (integer or float, but not np.nan)
- a boolean
- - a string with at least one Unicode letter (matching the regex ``\\p{L}``), underscore, !, ?, or number, but not
- "None", "", "N/A", or "-"
+ - a string with at least one Unicode letter (matching the regex ``\\p{L}``) or number, or at least one _, !, or ?
+ (The strings "None", "", "N/A", and "-" are considered invalid.)
- a PropertyElement whose "value" fulfills the above criteria
Args:
@@ -184,6 +184,21 @@ def check_notna(value: Optional[Any]) -> bool:
Returns:
True if the value is usable, False if it is N/A or otherwise unusable
+
+ Examples:
+ >>> check_notna(0) == True
+ >>> check_notna(False) == True
+ >>> check_notna("œ") == True
+ >>> check_notna("0") == True
+ >>> check_notna("_") == True
+ >>> check_notna("!") == True
+ >>> check_notna("?") == True
+ >>> check_notna(None) == False
+ >>> check_notna("None") == False
+ >>> check_notna() == False
+ >>> check_notna("") == False
+ >>> check_notna("-") == False
+ >>> check_notna(" ") == False
"""
if isinstance(value, PropertyElement):
diff --git a/knora/excel2xml.py b/knora/excel2xml.py
index 415072f88..9be64e13a 100644
--- a/knora/excel2xml.py
+++ b/knora/excel2xml.py
@@ -1189,9 +1189,12 @@ def make_text_prop(
# check value type
for val in values:
- if not isinstance(val.value, str) or not check_notna(val.value):
+ if not isinstance(val.value, str) or len(val.value) < 1:
raise BaseError(f"Failed validation in resource '{calling_resource}', property '{name}': "
f"'{val.value}' is not a valid string.")
+ if not check_notna(val.value):
+ warnings.warn(f"Warning for resource '{calling_resource}', property '{name}': "
+ f"'{val.value}' is probably not a usable string.", stacklevel=2)
# make xml structure of the valid values
prop_ = etree.Element(
@@ -1743,10 +1746,6 @@ def excel2xml(datafile: str, shortcode: str, default_ontology: str) -> None:
"text-prop": make_text_prop,
"uri-prop": make_uri_prop
}
- single_value_functions = [
- make_bitstream_prop,
- make_boolean_prop
- ]
if re.search(r"\.csv$", datafile):
# "utf_8_sig": an optional BOM at the start of the file will be skipped
# let the "python" engine detect the separator
@@ -1757,7 +1756,7 @@ def excel2xml(datafile: str, shortcode: str, default_ontology: str) -> None:
raise BaseError("The argument 'datafile' must have one of the extensions 'csv', 'xls', 'xlsx'")
# replace NA-like cells by NA
main_df = main_df.applymap(
- lambda x: x if pd.notna(x) and regex.search(r"[\w\p{L}]", str(x), flags=regex.U) else pd.NA
+ lambda x: x if pd.notna(x) and regex.search(r"[\p{L}\d_!?\-]", str(x), flags=regex.U) else pd.NA
)
# remove empty columns, so that the max_prop_count can be calculated without errors
main_df.dropna(axis="columns", how="all", inplace=True)
@@ -1847,7 +1846,7 @@ def excel2xml(datafile: str, shortcode: str, default_ontology: str) -> None:
property_elements: list[PropertyElement] = []
for i in range(1, max_prop_count + 1):
value = row[f"{i}_value"]
- if check_notna(value):
+ if pd.notna(value):
kwargs_propelem = {
"value": value,
"permissions": str(row.get(f"{i}_permissions"))
@@ -1861,13 +1860,25 @@ def excel2xml(datafile: str, shortcode: str, default_ontology: str) -> None:
kwargs_propelem["encoding"] = str(row[f"{i}_encoding"])
property_elements.append(PropertyElement(**kwargs_propelem))
+ elif check_notna(str(row.get(f"{i}_permissions"))):
+ raise BaseError(f"Excel row {int(str(index)) + 2} has an entry in column {i}_permissions, but not "
+ f"in {i}_value. Please note that cell contents that don't meet the requirements of "
+ r"the regex [\p{L}\d_!?\-] are considered inexistent.")
+
+ # validate property_elements
+ if len(property_elements) == 0:
+ raise BaseError(f"At least one value per property is required, but Excel row {int(str(index)) + 2}"
+ f"doesn't contain any values.")
+ if make_prop_function == make_boolean_prop and len(property_elements) != 1:
+ raise BaseError(f"A can only have a single value, but Excel row {int(str(index)) + 2} "
+ f"contains more than one values.")
# create the property and append it to resource
kwargs_propfunc: dict[str, Union[str, PropertyElement, list[PropertyElement]]] = {
"name": row["prop name"],
"calling_resource": resource_id
}
- if make_prop_function in single_value_functions and len(property_elements) == 1:
+ if make_prop_function == make_boolean_prop:
kwargs_propfunc["value"] = property_elements[0]
else:
kwargs_propfunc["value"] = property_elements
diff --git a/test/unittests/test_excel2xml.py b/test/unittests/test_excel2xml.py
index e41ef7a24..361edee64 100644
--- a/test/unittests/test_excel2xml.py
+++ b/test/unittests/test_excel2xml.py
@@ -5,6 +5,7 @@
from typing import Callable, Sequence, Union, Optional, Any
import numpy as np
+import pytest
from lxml import etree
from knora import excel2xml
@@ -104,6 +105,8 @@ def run_test(
xml_returned = method(**kwargs_to_generate_xml)
xml_returned = etree.tostring(xml_returned, encoding="unicode")
xml_returned = re.sub(r" xmlns(:.+?)?=\".+?\"", "", xml_returned) # remove all xml namespace declarations
+ xml_returned = xml_returned.replace("<", "<")
+ xml_returned = xml_returned.replace(">", ">")
testcase.assertEqual(xml_expected, xml_returned,
msg=f"Method {method.__name__} failed with kwargs {kwargs_to_generate_xml}")
@@ -348,11 +351,12 @@ def test_make_resptr_prop(self) -> None:
run_test(self, prop, method, different_values, invalid_values)
+ @pytest.mark.filterwarnings("ignore")
def test_make_text_prop(self) -> None:
prop = "text"
method = excel2xml.make_text_prop
- different_values = ["text_1", "text_2", "text_3", "text_4", "text_5"]
- invalid_values = [True, 10.0, 5]
+ different_values = ["text_1", " ", "!", "?", "-", "_", "None", ""]
+ invalid_values = [True, 10.0, 5, ""]
run_test(self, prop, method, different_values, invalid_values)
# test encoding="xml"
@@ -513,6 +517,7 @@ def test_create_json_list_mapping(self) -> None:
self.assertDictEqual(testlist_mapping_returned, testlist_mapping_expected)
+ @pytest.mark.filterwarnings("ignore")
def test_excel2xml(self) -> None:
# test the valid files, 3 times identical, but in the three formats XLSX, XLS, and CSV
with open("testdata/excel2xml-expected-output.xml") as f:
@@ -528,17 +533,20 @@ def test_excel2xml(self) -> None:
# test the invalid files
invalid_prefix = "testdata/invalid_testdata/excel2xml-testdata-invalid"
invalid_cases = [
- (f"{invalid_prefix}-id-propname-both.xlsx", "Exactly 1 of the 2 columns 'id' and 'prop name' must have an entry"),
- (f"{invalid_prefix}-id-propname-none.xlsx", "Exactly 1 of the 2 columns 'id' and 'prop name' must have an entry"),
- (f"{invalid_prefix}-missing-prop-permissions.xlsx", "Missing permissions for value .+ of property"),
- (f"{invalid_prefix}-missing-resource-label.xlsx", "Missing label for resource"),
- (f"{invalid_prefix}-missing-resource-permissions.xlsx", "Missing permissions for resource"),
- (f"{invalid_prefix}-missing-restype.xlsx", "Missing restype"),
- (f"{invalid_prefix}-no-bitstream-permissions.xlsx", "'file permissions' missing"),
- (f"{invalid_prefix}-nonexisting-proptype.xlsx", "Invalid prop type"),
+ (f"{invalid_prefix}-boolean-prop-two-values.xlsx", "A can only have a single value"),
+ (f"{invalid_prefix}-empty-property.xlsx", "At least one value per property is required"),
+ (f"{invalid_prefix}-id-propname-both.xlsx", "Exactly 1 of the 2 columns 'id' and 'prop name' must have an entry"),
+ (f"{invalid_prefix}-id-propname-none.xlsx", "Exactly 1 of the 2 columns 'id' and 'prop name' must have an entry"),
+ (f"{invalid_prefix}-missing-prop-permissions.xlsx", "Missing permissions for value .+ of property"),
+ (f"{invalid_prefix}-missing-resource-label.xlsx", "Missing label for resource"),
+ (f"{invalid_prefix}-missing-resource-permissions.xlsx", "Missing permissions for resource"),
+ (f"{invalid_prefix}-missing-restype.xlsx", "Missing restype"),
+ (f"{invalid_prefix}-no-bitstream-permissions.xlsx", "'file permissions' missing"),
+ (f"{invalid_prefix}-nonexisting-proptype.xlsx", "Invalid prop type"),
+ (f"{invalid_prefix}-single-invalid-value-for-property.xlsx", "has an entry in column \\d+_permissions, but not in \\d+_value")
]
- for file, regex in invalid_cases:
- with self.assertRaisesRegex(BaseError, regex, msg=f"Failed with file '{file}'"):
+ for file, _regex in invalid_cases:
+ with self.assertRaisesRegex(BaseError, _regex, msg=f"Failed with file '{file}'"):
excel2xml.excel2xml(file, "1234", f"excel2xml-invalid")
diff --git a/test/unittests/test_shared.py b/test/unittests/test_shared.py
index 97a8e0023..96c47af9c 100644
--- a/test/unittests/test_shared.py
+++ b/test/unittests/test_shared.py
@@ -45,12 +45,11 @@ def test_prepare_dataframe(self) -> None:
def test_check_notna(self) -> None:
na_values = [None, pd.NA, np.nan, "", " ", "-", ",", ".", "*", " ⳰", " ῀ ", " ῾ ", " \n\t ", "N/A", "n/a",
-
- "", ["a", "b"], pd.array(["a", "b"]), np.array([0, 1])]
+ "", "None", ["a", "b"], pd.array(["a", "b"]), np.array([0, 1])]
for na_value in na_values:
self.assertFalse(shared.check_notna(na_value), msg=f"Failed na_value: {na_value}")
- notna_values = [1, 0.1, True, False, "True", "False", r" \n\t ", "0", "_", "Ὅμηρος"]
+ notna_values = [1, 0.1, True, False, "True", "False", r" \n\t ", "0", "_", "Ὅμηρος", "!", "?"]
notna_values.extend([PropertyElement(x) for x in notna_values])
for notna_value in notna_values:
self.assertTrue(shared.check_notna(notna_value), msg=f"Failed notna_value: {notna_value}")
diff --git a/testdata/excel2xml-expected-output.xml b/testdata/excel2xml-expected-output.xml
index f8a56d961..b4de93afb 100644
--- a/testdata/excel2xml-expected-output.xml
+++ b/testdata/excel2xml-expected-output.xml
@@ -28,6 +28,8 @@
Homer
Ὅμηρος
+ ??
+ -
http://d-nb.info/gnd/11855333X
diff --git a/testdata/excel2xml-testdata.csv b/testdata/excel2xml-testdata.csv
index e8942bc84..93d88dc09 100644
--- a/testdata/excel2xml-testdata.csv
+++ b/testdata/excel2xml-testdata.csv
@@ -1,6 +1,6 @@
id,restype,label,ark,iri,created,permissions,file,file permissions,prop name,prop type,prop list,1_value,1_encoding,1_permissions,1_comment,2_value,2_encoding,2_permissions,2_comment,3_value,3_encoding,3_permissions,3_comment,4_value,4_encoding,4_permissions,4_comment, ,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
person_0,:Person,Homer,,,1999-12-31T23:59:59.9999999+01:00,res-default,,,,,,,,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,:hasName,text-prop,,Homer,utf8,prop-default,,Ὅμηρος,utf8,prop-default,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,:hasName,text-prop,,Homer,utf8,prop-default,,Ὅμηρος,utf8,prop-default,,??,utf8,prop-default,,-,utf8,prop-default,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,:hasIdentifier,uri-prop,,http://d-nb.info/gnd/11855333X,,prop-default,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,:hasExternalLink,uri-prop,,https://en.wikipedia.org/wiki/Homer,,prop-default,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
annotation_0,Annotation,Annotation to Homer,,,,res-default,,,,,,,,,,,,,,,,,,,,,,, ,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
@@ -54,4 +54,4 @@ link_thing_0,LinkObj,Link between person_0 and img_obj_6,ark:/72163/4123-31ec6ea
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
\ No newline at end of file
diff --git a/testdata/excel2xml-testdata.xls b/testdata/excel2xml-testdata.xls
index 405afe495..98d30bda9 100644
Binary files a/testdata/excel2xml-testdata.xls and b/testdata/excel2xml-testdata.xls differ
diff --git a/testdata/excel2xml-testdata.xlsx b/testdata/excel2xml-testdata.xlsx
index 1e04185f2..afe643a17 100644
Binary files a/testdata/excel2xml-testdata.xlsx and b/testdata/excel2xml-testdata.xlsx differ
diff --git a/testdata/invalid_testdata/excel2xml-testdata-invalid-boolean-prop-two-values.xlsx b/testdata/invalid_testdata/excel2xml-testdata-invalid-boolean-prop-two-values.xlsx
new file mode 100644
index 000000000..09202142a
Binary files /dev/null and b/testdata/invalid_testdata/excel2xml-testdata-invalid-boolean-prop-two-values.xlsx differ
diff --git a/testdata/invalid_testdata/excel2xml-testdata-invalid-empty-property.xlsx b/testdata/invalid_testdata/excel2xml-testdata-invalid-empty-property.xlsx
new file mode 100644
index 000000000..3e06eb045
Binary files /dev/null and b/testdata/invalid_testdata/excel2xml-testdata-invalid-empty-property.xlsx differ
diff --git a/testdata/invalid_testdata/excel2xml-testdata-invalid-single-invalid-value-for-property.xlsx b/testdata/invalid_testdata/excel2xml-testdata-invalid-single-invalid-value-for-property.xlsx
new file mode 100644
index 000000000..5cbbf1e3d
Binary files /dev/null and b/testdata/invalid_testdata/excel2xml-testdata-invalid-single-invalid-value-for-property.xlsx differ
diff --git a/testdata/test-data-systematic.xml b/testdata/test-data-systematic.xml
index b06ba9c30..d3c26fc8a 100644
--- a/testdata/test-data-systematic.xml
+++ b/testdata/test-data-systematic.xml
@@ -60,8 +60,14 @@
id="test_thing_1"
permissions="res-default">
- Dies ist ein einfacher Text ohne Markup
- Nochmals ein einfacher Text
+ Dies ist ein einfacher Text ohne Markup mit Tags, die aber nicht geparst werden.
+ Nochmals ein einfacher Text, dessen Tags geparst werden
+
+ _
+ !
+ ?
+ -
+ œ