diff --git a/Directory.Packages.props b/Directory.Packages.props index 77d02835..43c2f2ae 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,7 +15,7 @@ - + diff --git a/build/ProjectInfo.fs b/build/ProjectInfo.fs index cf0aa003..976bc619 100644 --- a/build/ProjectInfo.fs +++ b/build/ProjectInfo.fs @@ -5,19 +5,22 @@ open Helpers let project = "ARCtrl" +let allTestsProject = "tests/All" + /// Dotnet and JS test paths let testProjects = [ "tests/All" - //"tests/Core" - //"tests/Json" - //"tests/Spreadsheet" - //"tests/FileSystem" - //"tests/ARCtrl" - //"tests/Yaml" - //"tests/ValidationPackages" - //"tests/Contract" - //"tests/ROCrate" + "tests/ARCtrl" + "tests/Contract" + "tests/Core" + "tests/CWL" + "tests/FileSystem" + "tests/Json" + "tests/ROCrate" + "tests/Spreadsheet" + "tests/ValidationPackages" + "tests/Yaml" ] /// Native JS test paths diff --git a/build/TestTasks.fs b/build/TestTasks.fs index 6f4eb765..12f155be 100644 --- a/build/TestTasks.fs +++ b/build/TestTasks.fs @@ -6,6 +6,8 @@ open Fake.DotNet open ProjectInfo open BasicTasks open Fake.Core +open Fake.IO +open Fake.IO.Globbing.Operators module RunTests = @@ -33,19 +35,26 @@ module RunTests = Trace.traceImportant "Skipping JavaScript tests" ) + let prePareJsTests = BuildTask.create "PrepareJsTests" [] { + !! "tests/TestingUtils/TestResults" + |> Shell.cleanDirs + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/js") |> ignore + //System.IO.File.Copy(jsHelperFilePath, $"{allTestsProject}/js/{jsHelperFileName}") |> ignore + + } + + let runTestsJs = BuildTask.createFn "runTestsJS" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start Js tests" - for path in ProjectInfo.testProjects do - // Setup test results directory after clean - System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/js") |> ignore - // transpile js files from fsharp code - run dotnet $"fable {path} -o {path}/js --nocache" "" - - System.IO.File.Copy(jsHelperFilePath, $"{path}/js/{jsHelperFileName}") |> ignore - // run mocha in target path to execute tests - // "--timeout 20000" is used, because json schema validation takes a bit of time. - run node $"{path}/js/Main.js" "" + // Setup test results directory after clean + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/js") |> ignore + // transpile js files from fsharp code + run dotnet $"fable {allTestsProject} -o {allTestsProject}/js --nocache" "" + System.IO.File.Copy(jsHelperFilePath, $"{allTestsProject}/js/{jsHelperFileName}") |> ignore + // run mocha in target path to execute tests + // "--timeout 20000" is used, because json schema validation takes a bit of time. + run node $"{allTestsProject}/js/Main.js" "" else Trace.traceImportant "Skipping Js tests" ) @@ -65,13 +74,12 @@ module RunTests = let runTestsPy = BuildTask.createFn "runTestsPy" [clean] (fun tp -> if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start Python tests" - for path in ProjectInfo.testProjects do - // Setup test results directory after clean - System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/py") |> ignore - //transpile py files from fsharp code - run dotnet $"fable {path} -o {path}/py --lang python --nocache" "" - // run pyxpecto in target path to execute tests in python - run python $"{path}/py/main.py" "" + // Setup test results directory after clean + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/py") |> ignore + //transpile py files from fsharp code + run dotnet $"fable {allTestsProject} -o {allTestsProject}/py --lang python --nocache" "" + // run pyxpecto in target path to execute tests in python + run python $"{allTestsProject}/py/main.py" "" else Trace.traceImportant "Skipping Python tests" @@ -81,8 +89,7 @@ module RunTests = if tp.Context.Arguments |> List.exists (fun a -> a.ToLower() = skipTestsFlag.ToLower()) |> not then Trace.traceImportant "Start .NET tests" let dotnetRun = run dotnet "run" - testProjects - |> Seq.iter dotnetRun + dotnetRun allTestsProject else Trace.traceImportant "Skipping .NET tests" ) @@ -105,6 +112,7 @@ module RunTests = run python $"{p}/py/main.py" "" // transpile js files from fsharp code run dotnet $"fable {p} -o {p}/js" "" + System.IO.Directory.CreateDirectory("./tests/TestingUtils/TestResults/js") |> ignore System.IO.File.Copy(jsHelperFilePath, $"{p}/js/{jsHelperFileName}") |> ignore // run mocha in target path to execute tests // "--timeout 20000" is used, because json schema validation takes a bit of time. diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index f05bbc6c..fc1c4d8a 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -301,6 +301,59 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = #endif + member this.MakeDataFilesAbsolute() = + let filesPaths = this.FileSystem.Tree.ToFilePaths() |> set + let checkExistenceFromRoot = fun p -> filesPaths |> Set.contains p + match this.ISA with + | Some inv -> + inv.Studies |> Seq.iter (fun s -> + s.Tables |> Seq.iter (fun t -> + match t.TryGetInputColumn() with + | Some col when col.Header.IsDataColumn -> + col.Cells |> Array.iter (fun c -> + if c.AsData.FilePath.IsSome then + + let newFilePath = + c.AsData.GetAbsolutePathForStudy(s.Identifier,checkExistenceFromRoot) + c.AsData.FilePath <- Some newFilePath + ) + | _ -> () + match t.TryGetOutputColumn() with + | Some col when col.Header.IsDataColumn -> + col.Cells |> Array.iter (fun c -> + if c.AsData.FilePath.IsSome then + let newFilePath = + c.AsData.GetAbsolutePathForStudy(s.Identifier,checkExistenceFromRoot) + c.AsData.FilePath <- Some newFilePath + ) + | _ -> () + ) + ) + inv.Assays |> Seq.iter (fun a -> + a.Tables |> Seq.iter (fun t -> + match t.TryGetInputColumn() with + | Some col when col.Header.IsDataColumn -> + col.Cells |> Array.iter (fun c -> + if c.AsData.FilePath.IsSome then + let newFilePath = + c.AsData.GetAbsolutePathForAssay (a.Identifier,checkExistenceFromRoot) + c.AsData.FilePath <- Some newFilePath + ) + | _ -> () + match t.TryGetOutputColumn() with + | Some col when col.Header.IsDataColumn -> + col.Cells |> Array.iter (fun c -> + if c.AsData.FilePath.IsSome then + let newFilePath = + c.AsData.GetAbsolutePathForAssay (a.Identifier,checkExistenceFromRoot) + c.AsData.FilePath <- Some newFilePath + ) + | _ -> () + ) + ) + | None -> () + + //static member updateISA (isa : ISA.Investigation) (arc : ARC) : ARC = // raise (System.NotImplementedException()) @@ -701,11 +754,24 @@ type ARC(?isa : ArcInvestigation, ?cwl : unit, ?fs : FileSystem.FileSystem) = ARCtrl.Contract.Git.gitattributesFileName, ARCtrl.Contract.Git.gitattributesContract |] - static member fromROCrateJsonString (s:string) = - let isa = ARCtrl.Json.Decode.fromJsonString ARCtrl.Json.ARC.ROCrate.decoder s - ARC(?isa = isa) + static member fromDeprecatedROCrateJsonString (s:string) = + try + let isa = ARCtrl.Json.Decode.fromJsonString ARCtrl.Json.ARC.ROCrate.decoderDeprecated s + ARC(isa = isa) + with + | ex -> + failwithf "Could not parse deprecated ARC-RO-Crate metadata: \n%s" ex.Message + + static member fromROCrateJsonString (s:string) = + try + let isa = ARCtrl.Json.Decode.fromJsonString ARCtrl.Json.ARC.ROCrate.decoder s + ARC(isa = isa) + with + | ex -> + failwithf "Could not parse ARC-RO-Crate metadata: \n%s" ex.Message member this.ToROCrateJsonString(?spaces) = + this.MakeDataFilesAbsolute() ARCtrl.Json.ARC.ROCrate.encoder (Option.get _isa) |> ARCtrl.Json.Encode.toJsonString (ARCtrl.Json.Encode.defaultSpaces spaces) diff --git a/src/ARCtrl/ARCtrl.Javascript.fsproj b/src/ARCtrl/ARCtrl.Javascript.fsproj index ec77a70a..2d13112f 100644 --- a/src/ARCtrl/ARCtrl.Javascript.fsproj +++ b/src/ARCtrl/ARCtrl.Javascript.fsproj @@ -10,6 +10,7 @@ + @@ -48,7 +49,8 @@ - + + diff --git a/src/ARCtrl/ARCtrl.Python.fsproj b/src/ARCtrl/ARCtrl.Python.fsproj index 1859409e..bd18d04d 100644 --- a/src/ARCtrl/ARCtrl.Python.fsproj +++ b/src/ARCtrl/ARCtrl.Python.fsproj @@ -12,6 +12,7 @@ + @@ -50,7 +51,8 @@ - + + diff --git a/src/ARCtrl/ARCtrl.fsproj b/src/ARCtrl/ARCtrl.fsproj index 5bf53f9f..aacbe5f8 100644 --- a/src/ARCtrl/ARCtrl.fsproj +++ b/src/ARCtrl/ARCtrl.fsproj @@ -10,6 +10,7 @@ + @@ -48,13 +49,14 @@ - + + - - - + + + diff --git a/src/ARCtrl/ColumnIndex.fs b/src/ARCtrl/ColumnIndex.fs new file mode 100644 index 00000000..ffe0c6ac --- /dev/null +++ b/src/ARCtrl/ColumnIndex.fs @@ -0,0 +1,176 @@ +module ARCtrl.Process.ColumnIndex + +open ARCtrl + +let private tryInt (str:string) = + match System.Int32.TryParse str with + | true,int -> Some int + | _ -> None + +let orderName = "ColumnIndex" + +let createOrderComment (index : int) = + Comment.create(orderName,(string index)) + +let tryGetIndex (comments : ResizeArray) = + match comments |> CommentArray.tryItem orderName with + | Some ci -> + let i = comments |> Seq.findIndex (fun c -> c.Name = Some orderName) + comments.RemoveAt(i) + tryInt ci + | _ -> None + +let setOntologyAnnotationIndexInplace i (oa : OntologyAnnotation) = + oa.Comments.Add(createOrderComment i) + +let setOntologyAnnotationIndex i (oa : OntologyAnnotation) = + let oac = oa.Copy() + setOntologyAnnotationIndexInplace i oac + oac + +let tryGetOntologyAnnotationIndex (oa : OntologyAnnotation) = + oa.Comments |> tryGetIndex + +let tryGetParameterIndex (param : ProtocolParameter) = + param.ParameterName + |> Option.bind (fun oa -> + oa.Comments |> tryGetIndex + ) + +let tryGetParameterColumnIndex (paramValue : ProcessParameterValue) = + paramValue.Category + |> Option.bind tryGetParameterIndex + +let tryGetFactorIndex (factor : Factor) = + factor.FactorType + |> Option.bind (fun oa -> + oa.Comments |> tryGetIndex + ) + +let tryGetFactorColumnIndex (factorValue : FactorValue) = + factorValue.Category + |> Option.bind tryGetFactorIndex + +let tryGetCharacteristicIndex (characteristic : MaterialAttribute) = + characteristic.CharacteristicType + |> Option.bind (fun oa -> + oa.Comments |> tryGetIndex + ) + +let tryGetCharacteristicColumnIndex (characteristicValue : MaterialAttributeValue) = + characteristicValue.Category + |> Option.bind tryGetCharacteristicIndex + +let tryGetComponentIndex (comp : Component) = + comp.ComponentType + |> Option.bind (fun oa -> + oa.Comments |> tryGetIndex + ) + + +[] +module ColumnIndexExtensions = + + type OntologyAnnotation with + + /// Create a ISAJson Factor from ISATab string entries + static member fromStringWithColumnIndex (name:string) (term:string) (source:string) (accession:string) valueIndex = + Factor.fromString(name,term,source,accession,ResizeArray [|createOrderComment valueIndex|]) + + static member getColumnIndex(f) = tryGetOntologyAnnotationIndex f |> Option.get + + member this.GetColumnIndex() = tryGetOntologyAnnotationIndex this |> Option.get + + static member tryGetColumnIndex(f) = tryGetOntologyAnnotationIndex f + + member this.TryGetColumnIndex() = tryGetOntologyAnnotationIndex this + + static member setColumnIndex i oa = setOntologyAnnotationIndex i oa + + member this.SetColumnIndex i = setOntologyAnnotationIndexInplace i this + + type Factor with + + /// Create a ISAJson Factor from ISATab string entries + static member fromStringWithColumnIndex (name:string) (term:string) (source:string) (accession:string) valueIndex = + Factor.fromString(name,term,source,accession,ResizeArray [|createOrderComment valueIndex|]) + + static member getColumnIndex(f) = tryGetFactorIndex f |> Option.get + + member this.GetColumnIndex() = tryGetFactorIndex this |> Option.get + + static member tryGetColumnIndex(f) = tryGetFactorIndex f + + member this.TryGetColumnIndex() = tryGetFactorIndex this + + type FactorValue with + + static member getColumnIndex(f) = tryGetFactorColumnIndex f |> Option.get + + member this.GetColumnIndex() = tryGetFactorColumnIndex this |> Option.get + + static member tryGetColumnIndex(f) = tryGetFactorColumnIndex f + + member this.TryGetColumnIndex() = tryGetFactorColumnIndex this + + type MaterialAttribute with + + /// Create a ISAJson characteristic from ISATab string entries + static member fromStringWithColumnIndex (term:string) (source:string) (accession:string) valueIndex = + MaterialAttribute.fromString(term,source,accession,ResizeArray [|createOrderComment valueIndex|]) + + static member getColumnIndex(m) = tryGetCharacteristicIndex m |> Option.get + + member this.GetColumnIndex() = tryGetCharacteristicIndex this |> Option.get + + static member tryGetColumnIndex(m) = tryGetCharacteristicIndex m + + member this.TryGetColumnIndex() = tryGetCharacteristicIndex this + + type MaterialAttributeValue with + + static member getColumnIndex(m) = tryGetCharacteristicColumnIndex m |> Option.get + + member this.GetColumnIndex() = tryGetCharacteristicColumnIndex this |> Option.get + + static member tryGetColumnIndex(m) = tryGetCharacteristicColumnIndex m + + member this.TryGetColumnIndex() = tryGetCharacteristicColumnIndex this + + type ProtocolParameter with + + /// Create a ISAJson parameter from ISATab string entries + static member fromStringWithColumnIndex (term:string) (source:string) (accession:string) valueIndex = + ProtocolParameter.fromString(term,source,accession,ResizeArray [|createOrderComment valueIndex|]) + + static member getColumnIndex(p) = tryGetParameterIndex p |> Option.get + + member this.GetColumnIndex() = tryGetParameterIndex this |> Option.get + + static member tryGetColumnIndex(p) = tryGetParameterIndex p + + member this.TryGetColumnIndex() = tryGetParameterIndex this + + type ProcessParameterValue with + + static member getColumnIndex(p) = tryGetParameterColumnIndex p |> Option.get + + member this.GetColumnIndex() = tryGetParameterColumnIndex this |> Option.get + + static member tryGetColumnIndex(p) = tryGetParameterColumnIndex p + + member this.TryGetColumnIndex() = tryGetParameterColumnIndex this + + type Component with + + /// Create a ISAJson Factor from ISATab string entries + static member fromStringWithColumnIndex (name:string) (term:string) (source:string) (accession:string) valueIndex = + Component.fromISAString(name,term,source,accession,ResizeArray [|createOrderComment valueIndex|]) + + static member getColumnIndex(f) = tryGetComponentIndex f |> Option.get + + member this.GetColumnIndex() = tryGetComponentIndex this |> Option.get + + static member tryGetColumnIndex(f) = tryGetComponentIndex f + + member this.TryGetColumnIndex() = tryGetComponentIndex this diff --git a/src/ARCtrl/Conversion.fs b/src/ARCtrl/Conversion.fs new file mode 100644 index 00000000..8dcbf138 --- /dev/null +++ b/src/ARCtrl/Conversion.fs @@ -0,0 +1,1436 @@ +namespace ARCtrl.Conversion + +open ARCtrl.ROCrate +open ARCtrl +open ARCtrl.Helper +open System.Collections.Generic +//open ColumnIndex + +module DateTime = + + let tryFromString (s : string) = + try Json.Decode.fromJsonString Json.Decode.datetime s |> Some + with _ -> None + + let toString (d : System.DateTime) = + Json.Encode.dateTime d + |> Json.Encode.toJsonString 0 + +module ColumnIndex = + + open ARCtrl + + let private tryInt (str:string) = + match System.Int32.TryParse str with + | true,int -> Some int + | _ -> None + + let orderName = "columnIndex" + + let tryGetIndex (node : LDNode) = + match node.TryGetPropertyAsSingleton(orderName) with + | Some (:? string as ci) -> tryInt ci + | _ -> None + + let setIndex (node : LDNode) (index : int) = + node.SetProperty(orderName,(string index)) + + [] + module ColumnIndexExtensions = + + type LDNode with + + member this.GetColumnIndex() = tryGetIndex this |> Option.get + + member this.TryGetColumnIndex() = tryGetIndex this + + member this.SetColumnIndex (index : int) = setIndex this index + +/// Functions for transforming base level ARC Table and ISA Json Objects +type BaseTypes = + + static member composeComment (comment : ARCtrl.Comment) = + let name = match comment.Name with | Some n -> n | None -> failwith "Comment must have a name" + ARCtrl.ROCrate.Comment.create(name = name, ?text = comment.Value) + + static member decomposeComment (comment : LDNode, ?context : LDContext) = + let name = Comment.getNameAsString(comment, ?context = context) + let text = Comment.tryGetTextAsString(comment, ?context = context) + Comment(name = name,?value = text) + + static member composeDefinedTerm (term : OntologyAnnotation) = + let tan = term.TermAccessionAndOntobeeUrlIfShort |> Option.fromValueWithDefault "" + DefinedTerm.create(name = term.NameText, ?termCode = tan) + + static member decomposeDefinedTerm (term : LDNode, ?context : LDContext) = + let name = DefinedTerm.getNameAsString(term, ?context = context) + match DefinedTerm.tryGetTermCodeAsString(term, ?context = context) with + | Some t -> OntologyAnnotation.fromTermAnnotation(tan = t, name = name) + | None -> OntologyAnnotation.create(name = name) + + static member composePropertyValueFromOA (term : OntologyAnnotation) = + let tan = term.TermAccessionAndOntobeeUrlIfShort |> Option.fromValueWithDefault "" + PropertyValue.create(name = term.NameText, ?propertyID = tan) + + static member decomposePropertyValueToOA (term : LDNode, ?context : LDContext) = + let name = PropertyValue.getNameAsString(term, ?context = context) + match PropertyValue.tryGetPropertyIDAsString(term, ?context = context) with + | Some t -> OntologyAnnotation.fromTermAnnotation(tan = t, name = name) + | None -> OntologyAnnotation.create(name = name) + + /// Convert a CompositeCell to a ISA Value and Unit tuple. + static member valuesOfCell (value : CompositeCell) = + match value with + | CompositeCell.FreeText ("") -> None, None, None, None + | CompositeCell.FreeText (text) -> Some text, None, None, None + | CompositeCell.Term (term) when term.isEmpty() -> None, None, None, None + | CompositeCell.Term (term) when term.TANInfo.IsSome -> term.Name, Some term.TermAccessionAndOntobeeUrlIfShort, None, None + | CompositeCell.Term (term) -> term.Name, None, None, None + | CompositeCell.Unitized (text,unit) -> + let unitName, unitAccession = if unit.isEmpty() then None, None else unit.Name, Some unit.TermAccessionAndOntobeeUrlIfShort + (if text = "" then None else Some text), + None, + unitName, + unitAccession + | CompositeCell.Data (data) -> failwith "Data cell should not be parsed to isa value" + + static member termOfHeader (header : CompositeHeader) = + match header with + | CompositeHeader.Component oa + | CompositeHeader.Parameter oa + | CompositeHeader.Factor oa + | CompositeHeader.Characteristic oa -> + oa.NameText, if oa.TANInfo.IsSome then Some oa.TermAccessionAndOntobeeUrlIfShort else None + | h -> failwithf "header %O should not be parsed to isa value" h + + /// Convert a CompositeHeader and Cell tuple to a ISA Component + static member composeComponent (header : CompositeHeader) (value : CompositeCell) : LDNode = + let v,va,u,ua = BaseTypes.valuesOfCell value + let n, na = BaseTypes.termOfHeader header + PropertyValue.createComponent(n, ?value = v, ?propertyID = na, ?valueReference = va, ?unitCode = ua, ?unitText = u) + + /// Convert a CompositeHeader and Cell tuple to a ISA ProcessParameterValue + static member composeParameterValue (header : CompositeHeader) (value : CompositeCell) : LDNode = + let v,va,u,ua = BaseTypes.valuesOfCell value + let n, na = BaseTypes.termOfHeader header + PropertyValue.createParameterValue(n, ?value = v, ?propertyID = na, ?valueReference = va, ?unitCode = ua, ?unitText = u) + + /// Convert a CompositeHeader and Cell tuple to a ISA FactorValue + static member composeFactorValue (header : CompositeHeader) (value : CompositeCell) : LDNode = + let v,va,u,ua = BaseTypes.valuesOfCell value + let n, na = BaseTypes.termOfHeader header + PropertyValue.createFactorValue(n, ?value = v, ?propertyID = na, ?valueReference = va, ?unitCode = ua, ?unitText = u) + + /// Convert a CompositeHeader and Cell tuple to a ISA MaterialAttributeValue + static member composeCharacteristicValue (header : CompositeHeader) (value : CompositeCell) : LDNode = + let v,va,u,ua = BaseTypes.valuesOfCell value + let n, na = BaseTypes.termOfHeader header + PropertyValue.createCharacteristicValue(n, ?value = v, ?propertyID = na, ?valueReference = va, ?unitCode = ua, ?unitText = u) + + static member composeFreetextMaterialName (headerFT : string) (name : string) = + $"{headerFT}={name}" + + + static member composeFile (d : Data) : LDNode = + let dataType = d.DataType |> Option.map (fun dt -> dt.AsString) + File.create(d.NameText,d.NameText,?disambiguatingDescription = dataType, ?encodingFormat = d.Format, ?usageInfo = d.SelectorFormat) + + static member decomposeFile (f : LDNode, ?context : LDContext) : Data = + let dataType = File.tryGetDisambiguatingDescriptionAsString(f, ?context = context) |> Option.map DataFile.fromString + let format = File.tryGetEncodingFormatAsString(f, ?context = context) + let selectorFormat = File.tryGetUsageInfoAsString(f, ?context = context) + let data = Data(id = f.Id, name = File.getNameAsString(f, ?context = context), ?dataType = dataType, ?format = format, ?selectorFormat = selectorFormat) + data + + /// Convert a CompositeHeader and Cell tuple to a ISA ProcessInput + static member composeProcessInput (header : CompositeHeader) (value : CompositeCell) : LDNode = + match header with + | CompositeHeader.Input IOType.Source -> Sample.createSource(value.AsFreeText) + | CompositeHeader.Input IOType.Sample -> Sample.createSample(value.AsFreeText) + | CompositeHeader.Input IOType.Material -> Sample.createMaterial(value.AsFreeText) + | CompositeHeader.Input IOType.Data -> + match value with + | CompositeCell.FreeText ft -> + File.create(ft,ft) + | CompositeCell.Data od -> + BaseTypes.composeFile od + | _ -> failwithf "Could not parse input data %O" value + | CompositeHeader.Input (IOType.FreeText ft) -> + let n = LDNode(id = BaseTypes.composeFreetextMaterialName ft value.AsFreeText, schemaType = ResizeArray [ft]) + n.SetProperty(Sample.name, value.AsFreeText) + n + | _ -> + failwithf "Could not parse input header %O" header + + + /// Convert a CompositeHeader and Cell tuple to a ISA ProcessOutput + static member composeProcessOutput (header : CompositeHeader) (value : CompositeCell) : LDNode = + match header with + | CompositeHeader.Output IOType.Source + | CompositeHeader.Output IOType.Sample -> Sample.createSample(value.AsFreeText) + | CompositeHeader.Output IOType.Material -> Sample.createMaterial(value.AsFreeText) + | CompositeHeader.Output IOType.Data -> + match value with + | CompositeCell.FreeText ft -> + File.create(ft,ft) + | CompositeCell.Data od -> + BaseTypes.composeFile od + | _ -> failwithf "Could not parse output data %O" value + | CompositeHeader.Output (IOType.FreeText ft) -> + let n = LDNode(id = BaseTypes.composeFreetextMaterialName ft value.AsFreeText, schemaType = ResizeArray [ft]) + n.SetProperty(Sample.name, value.AsFreeText) + n + | _ -> failwithf "Could not parse output header %O" header + + static member headerOntologyOfPropertyValue (pv : LDNode, ?context : LDContext) = + let n = PropertyValue.getNameAsString(pv, ?context = context) + match PropertyValue.tryGetPropertyIDAsString(pv, ?context = context) with + | Some nRef -> OntologyAnnotation.fromTermAnnotation(tan = nRef, name = n) + | None -> OntologyAnnotation(name = n) + + /// Convert an ISA Value and Unit tuple to a CompositeCell + static member cellOfPropertyValue (pv : LDNode, ?context : LDContext) = + let v = PropertyValue.tryGetValueAsString(pv, ?context = context) + let vRef = PropertyValue.tryGetValueReference(pv, ?context = context) + let u = PropertyValue.tryGetUnitTextAsString(pv, ?context = context) + let uRef = PropertyValue.tryGetUnitCodeAsString(pv, ?context = context) + match vRef,u,uRef with + | Some vr, None, None -> + CompositeCell.Term (OntologyAnnotation.fromTermAnnotation(vr,?name = v)) + | None, Some u, None -> + CompositeCell.Unitized ((Option.defaultValue "" v),OntologyAnnotation(name = u)) + | None, _, Some uRef -> + CompositeCell.Unitized ((Option.defaultValue "" v),OntologyAnnotation.fromTermAnnotation(uRef, ?name = u)) + | None, None, None -> + CompositeCell.Term (OntologyAnnotation(?name = v)) + | _ -> + failwithf "Could not parse value %s with unit %O and unit reference %O" (Option.defaultValue "" v) u uRef + + /// Convert an ISA Component to a CompositeHeader and Cell tuple + static member decomposeComponent (c : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + let header = BaseTypes.headerOntologyOfPropertyValue(c, ?context = context) |> CompositeHeader.Component + let bodyCell = BaseTypes.cellOfPropertyValue (c, ?context = context) + header, bodyCell + + /// Convert an ISA ProcessParameterValue to a CompositeHeader and Cell tuple + static member decomposeParameterValue (c : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + let header = BaseTypes.headerOntologyOfPropertyValue (c, ?context = context) |> CompositeHeader.Parameter + let bodyCell = BaseTypes.cellOfPropertyValue (c, ?context = context) + header, bodyCell + + /// Convert an ISA FactorValue to a CompositeHeader and Cell tuple + static member decomposeFactorValue (c : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + let header = BaseTypes.headerOntologyOfPropertyValue (c, ?context = context) |> CompositeHeader.Factor + let bodyCell = BaseTypes.cellOfPropertyValue (c, ?context = context) + header, bodyCell + + /// Convert an ISA MaterialAttributeValue to a CompositeHeader and Cell tuple + static member decomposeCharacteristicValue (c : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + let header = BaseTypes.headerOntologyOfPropertyValue (c, ?context = context) |> CompositeHeader.Characteristic + let bodyCell = BaseTypes.cellOfPropertyValue (c, ?context = context) + header, bodyCell + + /// Convert an ISA ProcessOutput to a CompositeHeader and Cell tuple + static member decomposeProcessInput (pn : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + match pn with + | s when Sample.validateSource (s, ?context = context) -> CompositeHeader.Input IOType.Source, CompositeCell.FreeText (Sample.getNameAsString (s, ?context = context)) + | m when Sample.validateMaterial (m, ?context = context) -> CompositeHeader.Input IOType.Material, CompositeCell.FreeText (Sample.getNameAsString (m, ?context = context)) + | s when Sample.validate (s, ?context = context) -> CompositeHeader.Input IOType.Sample, CompositeCell.FreeText (Sample.getNameAsString (s, ?context = context)) + | d when File.validate (d, ?context = context) -> CompositeHeader.Input IOType.Data, CompositeCell.Data (BaseTypes.decomposeFile (d, ?context = context)) + | n -> CompositeHeader.Input (IOType.FreeText n.SchemaType.[0]), CompositeCell.FreeText (Sample.getNameAsString (n, ?context = context)) + + + static member decomposeProcessOutput (pn : LDNode, ?context : LDContext) : CompositeHeader*CompositeCell = + match pn with + | m when Sample.validateMaterial (m, ?context = context) -> CompositeHeader.Output IOType.Material, CompositeCell.FreeText (Sample.getNameAsString (m, ?context = context)) + | s when Sample.validate (s, ?context = context) -> CompositeHeader.Output IOType.Sample, CompositeCell.FreeText (Sample.getNameAsString (s, ?context = context)) + | d when File.validate (d, ?context = context) -> CompositeHeader.Output IOType.Data, CompositeCell.Data (BaseTypes.decomposeFile (d, ?context = context)) + | n -> CompositeHeader.Output (IOType.FreeText n.SchemaType.[0]), CompositeCell.FreeText (Sample.getNameAsString (n, ?context = context)) + + /// This function creates a string containing the name and the ontology short-string of the given ontology annotation term + /// + /// TechnologyPlatforms are plain strings in ISA-JSON. + /// + /// This function allows us, to parse them as an ontology term. + static member composeTechnologyPlatform (tp : OntologyAnnotation) = + match tp.TANInfo with + | Some _ -> + $"{tp.NameText} ({tp.TermAccessionShort})" + | None -> + $"{tp.NameText}" + + /// This function parses the given string containing the name and the ontology short-string of the given ontology annotation term + /// + /// TechnologyPlatforms are plain strings in ISA-JSON. + /// + /// This function allows us, to parse them as an ontology term. + static member decomposeTechnologyPlatform (name : string) = + let pattern = """^(?.+) \((?[^(]*:[^)]*)\)$""" + + match name with + | Regex.ActivePatterns.Regex pattern r -> + let oa = (r.Groups.Item "ontology").Value |> OntologyAnnotation.fromTermAnnotation + let v = (r.Groups.Item "value").Value + OntologyAnnotation.create(name = v, ?tan = oa.TermAccessionNumber, ?tsr = oa.TermSourceREF) + | _ -> + OntologyAnnotation.create(name = name) + + + + +open ColumnIndex +open ARCtrl.Helper.Regex.ActivePatterns + +/// Functions for parsing ArcTables to ISA json Processes and vice versa +type ProcessConversion = + + static member tryGetProtocolType (pv : LDNode, ?graph : LDGraph, ?context : LDContext) = + match LabProtocol.tryGetIntendedUseAsDefinedTerm(pv,?graph = graph, ?context = context) with + | Some dt -> + Some (BaseTypes.decomposeDefinedTerm(dt, ?context = context)) + | None -> + match LabProtocol.tryGetIntendedUseAsString(pv, ?context = context) with + | Some s -> Some (OntologyAnnotation.create(name = s)) + | None -> None + + static member composeProcessName (processNameRoot : string) (i : int) = + $"{processNameRoot}_{i}" + + static member decomposeProcessName (name : string) = + let pattern = """(?.+)_(?\d+)""" + + match name with + | Regex pattern r -> + (r.Groups.Item "name").Value, Some ((r.Groups.Item "num").Value |> int) + | _ -> + name, None + // Explanation of the Getter logic: + // The getter logic is used to treat every value of the table only once + // First, the headers are checked for what getter applies to the respective column. E.g. a ProtocolType getter will only return a function for parsing protocolType cells if the header depicts a protocolType. + // The appropriate getters are then applied in the context of the processGetter, parsing the cells of the matrix + + /// If the given headers depict a component, returns a function for parsing the values of the matrix to the values of this component + static member tryComponentGetter (generalI : int) (valueI : int) (valueHeader : CompositeHeader) = + match valueHeader with + | CompositeHeader.Component oa -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let c = BaseTypes.composeComponent valueHeader matrix.[generalI,i] + c.SetColumnIndex valueI + c + |> Some + | _ -> None + + /// If the given headers depict a parameter, returns a function for parsing the values of the matrix to the values of this type + static member tryParameterGetter (generalI : int) (valueI : int) (valueHeader : CompositeHeader) = + match valueHeader with + | CompositeHeader.Parameter oa -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let p = BaseTypes.composeParameterValue valueHeader matrix.[generalI,i] + p.SetColumnIndex valueI + p + |> Some + | _ -> None + + /// If the given headers depict a factor, returns a function for parsing the values of the matrix to the values of this type + static member tryFactorGetter (generalI : int) (valueI : int) (valueHeader : CompositeHeader) = + match valueHeader with + | CompositeHeader.Factor oa -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let f = BaseTypes.composeFactorValue valueHeader matrix.[generalI,i] + f.SetColumnIndex valueI + f + |> Some + | _ -> None + + /// If the given headers depict a protocolType, returns a function for parsing the values of the matrix to the values of this type + static member tryCharacteristicGetter (generalI : int) (valueI : int) (valueHeader : CompositeHeader) = + match valueHeader with + | CompositeHeader.Characteristic oa -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let c = BaseTypes.composeCharacteristicValue valueHeader matrix.[generalI,i] + c.SetColumnIndex valueI + c + |> Some + | _ -> None + + /// If the given headers depict a protocolType, returns a function for parsing the values of the matrix to the values of this type + static member tryGetProtocolTypeGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.ProtocolType -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + matrix.[generalI,i].AsTerm |> BaseTypes.composeDefinedTerm + |> Some + | _ -> None + + + /// If the given headers depict a protocolREF, returns a function for parsing the values of the matrix to the values of this type + static member tryGetProtocolREFGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.ProtocolREF -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + matrix.[generalI,i].AsFreeText + |> Some + | _ -> None + + /// If the given headers depict a protocolDescription, returns a function for parsing the values of the matrix to the values of this type + static member tryGetProtocolDescriptionGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.ProtocolDescription -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + matrix.[generalI,i].AsFreeText + |> Some + | _ -> None + + /// If the given headers depict a protocolURI, returns a function for parsing the values of the matrix to the values of this type + static member tryGetProtocolURIGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.ProtocolUri -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + matrix.[generalI,i].AsFreeText + |> Some + | _ -> None + + /// If the given headers depict a protocolVersion, returns a function for parsing the values of the matrix to the values of this type + static member tryGetProtocolVersionGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.ProtocolVersion -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + matrix.[generalI,i].AsFreeText + |> Some + | _ -> None + + /// If the given headers depict an input, returns a function for parsing the values of the matrix to the values of this type + static member tryGetInputGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.Input io -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + BaseTypes.composeProcessInput header matrix.[generalI,i] + |> Some + | _ -> None + + /// If the given headers depict an output, returns a function for parsing the values of the matrix to the values of this type + static member tryGetOutputGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.Output io -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + BaseTypes.composeProcessOutput header matrix.[generalI,i] + |> Some + | _ -> None + + /// If the given headers depict a comment, returns a function for parsing the values of the matrix to the values of this type + static member tryGetCommentGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.Comment c -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + //Comment.create(c,matrix.[generalI,i].AsFreeText) + Comment(c,matrix.[generalI,i].AsFreeText).ToString() + |> Some + | _ -> None + + static member tryGetPerformerGetter (generalI : int) (header : CompositeHeader) = + match header with + | CompositeHeader.Performer -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let performer = matrix.[generalI,i].AsFreeText + let person = ARCtrl.ROCrate.Person.create(performer,performer) + person + |> Some + | _ -> None + + /// Given the header sequence of an ArcTable, returns a function for parsing each row of the table to a process + static member getProcessGetter (processNameRoot : string) (headers : CompositeHeader seq) = + + let headers = + headers + |> Seq.indexed + + let valueHeaders = + headers + |> Seq.filter (snd >> fun h -> h.IsCvParamColumn) + |> Seq.indexed + |> Seq.toList + + let charGetters = + valueHeaders + |> List.choose (fun (valueI,(generalI,header)) -> ProcessConversion.tryCharacteristicGetter generalI valueI header) + + let factorValueGetters = + valueHeaders + |> List.choose (fun (valueI,(generalI,header)) -> ProcessConversion.tryFactorGetter generalI valueI header) + + let parameterValueGetters = + valueHeaders + |> List.choose (fun (valueI,(generalI,header)) -> ProcessConversion.tryParameterGetter generalI valueI header) + + let componentGetters = + valueHeaders + |> List.choose (fun (valueI,(generalI,header)) -> ProcessConversion.tryComponentGetter generalI valueI header) + + let protocolTypeGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetProtocolTypeGetter generalI header) + + let protocolREFGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetProtocolREFGetter generalI header) + + let protocolDescriptionGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetProtocolDescriptionGetter generalI header) + + let protocolURIGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetProtocolURIGetter generalI header) + + let protocolVersionGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetProtocolVersionGetter generalI header) + + let performerGetter = + headers + |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetPerformerGetter generalI header) + + let commentGetters = + headers + |> Seq.choose (fun (generalI,header) -> ProcessConversion.tryGetCommentGetter generalI header) + |> Seq.toList + + let inputGetter = + match headers |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetInputGetter generalI header) with + | Some inputGetter -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let chars = charGetters |> Seq.map (fun f -> f matrix i) |> ResizeArray + let input = inputGetter matrix i + + if chars.Count > 0 then + Sample.setAdditionalProperties(input,chars) + input + |> ResizeArray.singleton + | None when charGetters.Length <> 0 -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let chars = charGetters |> Seq.map (fun f -> f matrix i) |> ResizeArray + Sample.createSample(name = $"{processNameRoot}_Input_{i}", additionalProperties = chars) + |> ResizeArray.singleton + | None -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + ResizeArray [] + + // This is a little more complex, as data and material objects can't contain factors. So in the case where the output of the table is a data object but factors exist. An additional sample object with the same name is created to contain the factors. + let outputGetter = + match headers |> Seq.tryPick (fun (generalI,header) -> ProcessConversion.tryGetOutputGetter generalI header) with + | Some outputGetter -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let factors = factorValueGetters |> Seq.map (fun f -> f matrix i) |> ResizeArray + let output = outputGetter matrix i + if factors.Count > 0 then + Sample.setAdditionalProperties(output,factors) + output + |> ResizeArray.singleton + | None when factorValueGetters.Length <> 0 -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + let factors = factorValueGetters |> Seq.map (fun f -> f matrix i) |> ResizeArray + Sample.createSample(name = $"{processNameRoot}_Output_{i}", additionalProperties = factors) + |> ResizeArray.singleton + | None -> + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + ResizeArray [] + fun (matrix : System.Collections.Generic.Dictionary<(int * int),CompositeCell>) i -> + + let rowCount = matrix.Keys |> Seq.map snd |> Seq.max |> (+) 1 + let pn = + if rowCount = 1 then processNameRoot + else ProcessConversion.composeProcessName processNameRoot i + + let paramvalues = parameterValueGetters |> List.map (fun f -> f matrix i) |> Option.fromValueWithDefault [] |> Option.map ResizeArray + //let parameters = paramvalues |> Option.map (List.map (fun pv -> pv.Category.Value)) + + let comments = commentGetters |> List.map (fun f -> f matrix i) |> Option.fromValueWithDefault [] |> Option.map ResizeArray + + let components = componentGetters |> List.map (fun f -> f matrix i) |> Option.fromValueWithDefault [] |> Option.map ResizeArray + + let protocol : LDNode option = + let name = (protocolREFGetter |> Option.map (fun f -> f matrix i)) + let protocolId = LabProtocol.genId(?name = name, processName = processNameRoot) + LabProtocol.create( + id = protocolId, + ?name = name, + ?description = (protocolDescriptionGetter |> Option.map (fun f -> f matrix i)), + ?intendedUse = (protocolTypeGetter |> Option.map (fun f -> f matrix i)), + //?comments = comments, + ?url = (protocolURIGetter |> Option.map (fun f -> f matrix i)), + ?version = (protocolVersionGetter |> Option.map (fun f -> f matrix i)), + ?labEquipments = components + ) + |> Some + + let input,output = inputGetter matrix i, outputGetter matrix i + + let agent = performerGetter |> Option.map (fun f -> f matrix i) + + LabProcess.create( + name = pn, + objects = input, + results = output, + ?agent = agent, + ?executesLabProtocol = protocol, + ?parameterValues = paramvalues, + ?disambiguatingDescriptions = comments + + ) + + /// Groups processes by their name, or by the name of the protocol they execute + /// + /// Process names are taken from the Worksheet name and numbered: SheetName_1, SheetName_2, etc. + /// + /// This function decomposes this name into a root name and a number, and groups processes by root name. + static member groupProcesses (processes : LDNode list, ?graph : LDGraph, ?context : LDContext) = + processes + |> List.groupBy (fun p -> + match LabProcess.tryGetNameAsString (p, ?context = context), LabProcess.tryGetExecutesLabProtocol(p,?graph = graph, ?context = context) with + | Some name, _ when ProcessConversion.decomposeProcessName name |> snd |> Option.isSome -> + ProcessConversion.decomposeProcessName name |> fst + | _, Some protocol when LabProtocol.tryGetNameAsString (protocol, ?context = context) |> Option.isSome -> + LabProtocol.tryGetNameAsString (protocol, ?context = context) |> Option.defaultValue "" + | Some name, _ when name.Contains "_" -> + let lastUnderScoreIndex = name.LastIndexOf '_' + name.Remove lastUnderScoreIndex + | Some name, _ -> + name + | _, Some protocol -> + protocol.Id + | _ -> + Identifier.createMissingIdentifier() + ) + + /// Merges processes with the same name, protocol and param values + //let mergeIdenticalProcesses (processes : list) = + // processes + // |> List.groupBy (fun x -> + // if x.Name.IsSome && (x.Name.Value |> Process.decomposeName |> snd).IsSome then + // (x.Name.Value |> Process.decomposeName |> fst), HashCodes.boxHashOption x.ExecutesProtocol, x.ParameterValues |> Option.map HashCodes.boxHashSeq, x.Comments |> Option.map HashCodes.boxHashSeq + // elif x.ExecutesProtocol.IsSome && x.ExecutesProtocol.Value.Name.IsSome then + // x.ExecutesProtocol.Value.Name.Value, HashCodes.boxHashOption x.ExecutesProtocol, x.ParameterValues |> Option.map HashCodes.boxHashSeq, x.Comments |> Option.map HashCodes.boxHashSeq + // else + // Identifier.createMissingIdentifier(), HashCodes.boxHashOption x.ExecutesProtocol, x.ParameterValues |> Option.map HashCodes.boxHashSeq, x.Comments |> Option.map HashCodes.boxHashSeq + // ) + // |> fun l -> + // l + // |> List.mapi (fun i ((n,_,_,_),processes) -> + // let pVs = processes.[0].ParameterValues + // let inputs = processes |> List.collect (fun p -> p.Inputs |> Option.defaultValue []) |> Option.fromValueWithDefault [] + // let outputs = processes |> List.collect (fun p -> p.Outputs |> Option.defaultValue []) |> Option.fromValueWithDefault [] + // let n = if l.Length > 1 then Process.composeName n i else n + // Process.create(Name = n,?ExecutesProtocol = processes.[0].ExecutesProtocol,?ParameterValues = pVs,?Inputs = inputs,?Outputs = outputs,?Comments = processes.[0].Comments) + // ) + + + // Transform a isa json process into a isa tab row, where each row is a header+value list + static member processToRows (p : LDNode, ?graph : LDGraph, ?context : LDContext) = + let pvs = + LabProcess.getParameterValues(p, ?graph = graph, ?context = context) + |> ResizeArray.map (fun ppv -> BaseTypes.decomposeParameterValue(ppv, ?context = context), ColumnIndex.tryGetIndex ppv) + // Get the component + let components = + match LabProcess.tryGetExecutesLabProtocol(p, ?graph = graph, ?context = context) with + | Some prot -> + LabProtocol.getComponents(prot, ?graph = graph, ?context = context) + |> ResizeArray.map (fun ppv -> BaseTypes.decomposeComponent(ppv, ?context = context), ColumnIndex.tryGetIndex ppv) + | None -> ResizeArray [] + // Get the values of the protocol + let protVals = + match LabProcess.tryGetExecutesLabProtocol(p, ?graph = graph, ?context = context) with + | Some prot -> + [ + match LabProtocol.tryGetNameAsString (prot, ?context = context) with | Some name -> yield (CompositeHeader.ProtocolREF, CompositeCell.FreeText name) | None -> () + match LabProtocol.tryGetDescriptionAsString (prot, ?context = context) with | Some desc -> yield (CompositeHeader.ProtocolDescription, CompositeCell.FreeText desc) | None -> () + match LabProtocol.tryGetUrl (prot, ?context = context) with | Some uri -> yield (CompositeHeader.ProtocolUri, CompositeCell.FreeText uri) | None -> () + match LabProtocol.tryGetVersionAsString(prot, ?context = context) with | Some version -> yield (CompositeHeader.ProtocolVersion, CompositeCell.FreeText version) | None -> () + match ProcessConversion.tryGetProtocolType(prot, ?graph = graph, ?context = context) with + | Some intendedUse -> yield (CompositeHeader.ProtocolType, CompositeCell.Term intendedUse) + | None -> () + ] + | None -> [] + let comments = + LabProcess.getDisambiguatingDescriptionsAsString(p, ?context = context) + |> ResizeArray.map (fun c -> + let c = Comment.fromString c + CompositeHeader.Comment (Option.defaultValue "" c.Name), + CompositeCell.FreeText (Option.defaultValue "" c.Value) + ) + + let inputs = LabProcess.getObjects(p, ?graph = graph, ?context = context) + let outputs = LabProcess.getResults(p, ?graph = graph, ?context = context) + + let inputs,outputs = + if inputs.Count = 0 && outputs.Count <> 0 then + ResizeArray.create outputs.Count None, + ResizeArray.map Option.Some outputs + elif inputs.Count <> 0 && outputs.Count = 0 then + ResizeArray.map Option.Some inputs, + ResizeArray.create inputs.Count None + else + ResizeArray.map Option.Some inputs, + ResizeArray.map Option.Some outputs + + + if inputs.Count = 0 && outputs.Count = 0 then + let vals = + [ + yield! components + yield! pvs + ] + |> List.sortBy (snd >> Option.defaultValue 10000) + |> List.map fst + [ + yield! protVals + yield! vals + yield! comments + ] + |> ResizeArray.singleton + else + // zip the inputs and outpus so they are aligned as rows + outputs + |> ResizeArray.zip inputs + // This grouping here and the picking of the "inputForCharas" etc is done, so there can be rows where data do have characteristics, which is not possible in isa json + |> ResizeArray.map (fun (i,o) -> + let chars = + match i with + | Some i -> + Sample.getCharacteristics(i, ?graph = graph, ?context = context) + |> ResizeArray.map (fun cv -> BaseTypes.decomposeCharacteristicValue(cv, ?context = context), ColumnIndex.tryGetIndex cv) + | None -> ResizeArray [] + let factors = + match o with + | Some o -> + Sample.getFactors(o, ?graph = graph, ?context = context) + |> ResizeArray.map (fun fv -> BaseTypes.decomposeFactorValue(fv, ?context = context), ColumnIndex.tryGetIndex fv) + | None -> ResizeArray [] + + + let vals = + [ + yield! chars + yield! components + yield! pvs + yield! factors + ] + |> List.sortBy (snd >> Option.defaultValue 10000) + |> List.map fst + [ + if i.IsSome then yield BaseTypes.decomposeProcessInput(i.Value, ?context = context) + yield! protVals + yield! vals + yield! comments + if o.IsSome then yield BaseTypes.decomposeProcessOutput(o.Value, ?context = context) + ] + ) + +//[] +//module CoreTypeExtensions = + +// type CompositeHeader with + +// member this.TryParameter() = +// match this with +// | CompositeHeader.Parameter oa -> Some (DefinedTerm.create (ParameterName = oa)) +// | _ -> None + +// member this.TryFactor() = +// match this with +// | CompositeHeader.Factor oa -> Some (Factor.create(FactorType = oa)) +// | _ -> None + +// member this.TryCharacteristic() = +// match this with +// | CompositeHeader.Characteristic oa -> Some (MaterialAttribute.create(CharacteristicType = oa)) +// | _ -> None + +// member this.TryComponent() = +// match this with +// | CompositeHeader.Component oa -> Some (Component.create(componentType = oa)) +// | _ -> None + +// type CompositeCell with + +// /// +// /// This function is used to improve interoperability with ISA-JSON types. It is not recommended for default ARCtrl usage. +// /// +// /// +// /// +// static member fromValue(value : Value, ?unit : OntologyAnnotation) = +// BaseTypes.cellOfValue (Some value) unit + + +module CompositeRow = + + let toProtocol (tableName : string) (row : (CompositeHeader*CompositeCell) seq) = + let id = tableName + row + |> Seq.fold (fun p hc -> + match hc with + | CompositeHeader.ProtocolType, CompositeCell.Term oa -> + LabProtocol.setIntendedUseAsDefinedTerm(p, BaseTypes.composeDefinedTerm oa) + + | CompositeHeader.ProtocolVersion, CompositeCell.FreeText v -> + LabProtocol.setVersionAsString(p,v) + + | CompositeHeader.ProtocolUri, CompositeCell.FreeText v -> + LabProtocol.setUrl(p,v) + + | CompositeHeader.ProtocolDescription, CompositeCell.FreeText v -> + LabProtocol.setDescriptionAsString(p,v) + + | CompositeHeader.ProtocolREF, CompositeCell.FreeText v -> + LabProtocol.setNameAsString(p,v) + //| CompositeHeader.Parameter oa, _ -> + // DefinedTerm.create + // let pp = ProtocolParameter.create(ParameterName = oa) + // Protocol.addParameter (pp) p + | CompositeHeader.Component _, CompositeCell.Term _ + | CompositeHeader.Component _, CompositeCell.Unitized _ -> + let c = BaseTypes.composeComponent (fst hc) (snd hc) + let newC = ResizeArray.appendSingleton c (LabProtocol.getLabEquipments(p)) + LabProtocol.setLabEquipments(p,newC) + | _ -> () + p + ) (LabProtocol.create(id = id, name = tableName)) + +[] +module TableTypeExtensions = + + type ArcTable with + + /// Create a new table from an ISA protocol. + /// + /// The table will have at most one row, with the protocol information and the component values + static member fromProtocol (p : LDNode, ?graph : LDGraph, ?context : LDContext) : ArcTable = + + let name = LabProtocol.getNameAsString(p, ?context = context) + let t = ArcTable.init name + + //for pp in LabProtocol.getPa p.Parameters |> Option.defaultValue [] do + + // //t.AddParameterColumn(pp, ?index = pp.TryGetColumnIndex()) + + // t.AddColumn(CompositeHeader.Parameter pp.ParameterName.Value, ?index = pp.TryGetColumnIndex()) + + for c in LabProtocol.getComponents(p, ?graph = graph, ?context = context) do + let h,v = BaseTypes.decomposeComponent(c, ?context = context) + t.AddColumn( + h, + cells = Array.singleton v, + ?index = c.TryGetColumnIndex()) + LabProtocol.tryGetDescriptionAsString(p, ?context = context) |> Option.map (fun d -> t.AddProtocolDescriptionColumn([|d|])) |> ignore + LabProtocol.tryGetVersionAsString(p, ?context = context) |> Option.map (fun d -> t.AddProtocolVersionColumn([|d|])) |> ignore + ProcessConversion.tryGetProtocolType(p, ?context =context) |> Option.map (fun d -> t.AddProtocolTypeColumn([|d|])) |> ignore + LabProtocol.tryGetUrl(p, ?context = context) |> Option.map (fun d -> t.AddProtocolUriColumn([|d|])) |> ignore + t.AddProtocolNameColumn([|name|]) + t + + /// Returns the list of protocols executed in this ArcTable + member this.GetProtocols() : LDNode list = + + if this.RowCount = 0 then + this.Headers + |> Seq.fold (fun (p : LDNode) h -> + match h with + //| CompositeHeader.Parameter oa -> + // let pp = ProtocolParameter.create(ParameterName = oa) + // Protocol.addParameter (pp) p + | CompositeHeader.Component oa -> + let n, na = oa.NameText, oa.TermAccessionOntobeeUrl + let c = PropertyValue.createComponent(n, "Empty Component Value", propertyID = na) + let newC = ResizeArray.appendSingleton c (LabProtocol.getLabEquipments p) + LabProtocol.setLabEquipments(p,newC) + | _ -> () + p + ) (LabProtocol.create(id = Identifier.createMissingIdentifier(), name = this.Name)) + |> List.singleton + else + List.init this.RowCount (fun i -> + this.GetRow(i, SkipValidation = true) + |> Seq.zip this.Headers + |> CompositeRow.toProtocol this.Name + ) + |> List.distinct + + /// Returns the list of processes specidified in this ArcTable + member this.GetProcesses() : LDNode list = + if this.RowCount = 0 then + //let input = ResizeArray [Sample.createSample(name = $"{this.Name}_Input", additionalProperties = ResizeArray [])] + //let output = ResizeArray [Sample.createSample(name = $"{this.Name}_Output", additionalProperties = ResizeArray [])] + LabProcess.create(name = this.Name(*, objects = input, results = output*)) + |> List.singleton + else + let getter = ProcessConversion.getProcessGetter this.Name this.Headers + [ + for i in 0..this.RowCount-1 do + yield getter this.Values i + ] + //|> ProcessConversion.mergeIdenticalProcesses + + + /// Create a new table from a list of processes + /// + /// The name will be used as the sheet name + /// + /// The processes SHOULD have the same headers, or even execute the same protocol + static member fromProcesses(name,ps : LDNode list, ?graph : LDGraph, ?context : LDContext) : ArcTable = + ps + |> List.collect (fun p -> ProcessConversion.processToRows(p,?context = context,?graph = graph) |> List.ofSeq) + |> ArcTableAux.Unchecked.alignByHeaders true + |> fun (headers, rows) -> ArcTable.create(name,headers,rows) + + type ArcTables with + + /// Return a list of all the processes in all the tables. + member this.GetProcesses() : LDNode list = + this.Tables + |> Seq.toList + |> List.collect (fun t -> t.GetProcesses()) + + /// Create a collection of tables from a list of processes. + /// + /// For this, the processes are grouped by nameroot ("nameroot_1", "nameroot_2" ...) or exectued protocol if no name exists + /// + /// Then each group is converted to a table with this nameroot as sheetname + static member fromProcesses (ps : LDNode list, ?graph : LDGraph, ?context : LDContext) : ArcTables = + ps + |> ProcessConversion.groupProcesses + |> List.map (fun (name,ps) -> + ps + |> List.collect (fun p -> ProcessConversion.processToRows(p,?graph = graph, ?context = context) |> List.ofSeq) + |> fun rows -> ArcTableAux.Unchecked.alignByHeaders true rows + |> fun (headers, rows) -> ArcTable.create(name,headers,rows) + ) + |> ResizeArray + |> ArcTables + + + +type PersonConversion = + + static member orcidKey = "ORCID" + + static member composeAffiliation (affiliation : string) : LDNode = + try + ARCtrl.Json.Decode.fromJsonString Json.LDNode.decoder affiliation + with + | _ -> Organization.create(name = affiliation) + + static member decomposeAffiliation (affiliation : LDNode, ?context : LDContext) : string = + let hasOnlyName = + affiliation.GetPropertyNames(?context = context) + |> Seq.filter(fun n -> n <> Organization.name) + |> Seq.isEmpty + if hasOnlyName then + Organization.getNameAsString(affiliation, ?context = context) + else + Json.LDNode.encoder affiliation + |> ARCtrl.Json.Encode.toJsonString 0 + + static member composeAddress (address : string) : obj = + try + ARCtrl.Json.Decode.fromJsonString Json.LDNode.decoder address + |> box + with + | _ -> address + + static member decomposeAddress (address : obj) : string = + match address with + | :? string as s -> s + | :? LDNode as n -> + Json.LDNode.encoder n + |> ARCtrl.Json.Encode.toJsonString 0 + | _ -> failwith "Address must be a string or a Json.LDNode" + + static member composePerson (person : ARCtrl.Person) = + let givenName = + match person.FirstName with + | Some fn -> fn + | None -> failwith "Person must have a given name" + let jobTitles = + person.Roles + |> ResizeArray.map BaseTypes.composeDefinedTerm + |> Option.fromSeq + let disambiguatingDescriptions = + person.Comments + |> ResizeArray.map (fun c -> c.ToString()) + |> Option.fromSeq + let address = + person.Address + |> Option.map PersonConversion.composeAddress + let affiliation = + person.Affiliation + |> Option.map PersonConversion.composeAffiliation + ARCtrl.ROCrate.Person.create(givenName, ?orcid = person.ORCID, ?affiliation = affiliation, ?email = person.EMail, ?familyName = person.LastName, ?jobTitles = jobTitles, ?additionalName = person.MidInitials, ?address = address, ?disambiguatingDescriptions = disambiguatingDescriptions, ?faxNumber = person.Fax, ?telephone = person.Phone) + + static member decomposePerson (person : LDNode, ?graph : LDGraph, ?context : LDContext) = + let orcid = ORCID.tryGetOrcidNumber person.Id + let address = + match Person.tryGetAddressAsString(person, ?context = context) with + | Some s -> + Some s + | None -> + match Person.tryGetAddressAsPostalAddress(person, ?graph = graph, ?context = context) with + | Some a -> Some (PersonConversion.decomposeAddress a) + | None -> None + let roles = + Person.getJobTitlesAsDefinedTerm(person, ?graph = graph, ?context = context) + |> ResizeArray.map (fun r -> BaseTypes.decomposeDefinedTerm(r, ?context = context)) + let comments = + Person.getDisambiguatingDescriptionsAsString(person, ?context = context) + |> ResizeArray.map Comment.fromString + let affiliation = + Person.tryGetAffiliation(person, ?graph = graph, ?context = context) + |> Option.map (fun a -> PersonConversion.decomposeAffiliation(a, ?context = context)) + ARCtrl.Person.create( + firstName = Person.getGivenNameAsString(person, ?context = context), + ?lastName = Person.tryGetFamilyNameAsString(person, ?context = context), + ?midInitials = Person.tryGetAdditionalNameAsString(person, ?context = context), + ?email = Person.tryGetEmailAsString(person, ?context = context), + ?fax = Person.tryGetFaxNumberAsString(person, ?context = context), + ?phone = Person.tryGetTelephoneAsString(person, ?context = context), + ?orcid = orcid, + ?affiliation = affiliation, + roles = roles, + ?address = address, + comments = comments + ) + + +type ScholarlyArticleConversion = + + + static member doiKey = "DOI" + + static member doiURL = "http://purl.obolibrary.org/obo/OBI_0002110" + + static member pubmedIDKey = "PubMedID" + + static member pubmedIDURL = "http://purl.obolibrary.org/obo/OBI_0001617" + + static member composeDOI (doi : string) : LDNode = + PropertyValue.create(name = ScholarlyArticleConversion.doiKey, value = doi, propertyID = ScholarlyArticleConversion.doiURL) + + static member tryDecomposeDOI (doi : LDNode, ?context : LDContext) : string option = + match + PropertyValue.tryGetNameAsString(doi, ?context = context), + PropertyValue.tryGetValueAsString(doi, ?context = context), + PropertyValue.tryGetPropertyIDAsString(doi, ?context = context) + with + | Some name, Some value, Some id when name = ScholarlyArticleConversion.doiKey && id = ScholarlyArticleConversion.doiURL -> + Some value + | _ -> None + + static member composePubMedID (pubMedID : string) : LDNode = + PropertyValue.create(name = ScholarlyArticleConversion.pubmedIDKey, value = pubMedID, propertyID = ScholarlyArticleConversion.pubmedIDURL) + + static member tryDecomposePubMedID (pubMedID : LDNode, ?context : LDContext) : string option = + match + PropertyValue.tryGetNameAsString(pubMedID, ?context = context), + PropertyValue.tryGetValueAsString(pubMedID, ?context = context), + PropertyValue.tryGetPropertyIDAsString(pubMedID, ?context = context) + with + | Some name, Some value, Some id when name = ScholarlyArticleConversion.pubmedIDKey && id = ScholarlyArticleConversion.pubmedIDURL -> + Some value + | _ -> None + + static member composeAuthor (author : string) : LDNode = + try + ARCtrl.Json.Decode.fromJsonString Json.LDNode.decoder author + with + | _ -> ARCtrl.ROCrate.Person.create(givenName = author) + + static member splitAuthors (a : string) = + let mutable bracketCount = 0 + let authors = ResizeArray() + let sb = System.Text.StringBuilder() + for c in a do + if c = '{' then + bracketCount <- bracketCount + 1 + sb.Append(c) |> ignore + elif c = '}' then + bracketCount <- bracketCount - 1 + sb.Append(c) |> ignore + elif c = ',' && bracketCount = 0 then + authors.Add(sb.ToString()) + sb.Clear() |> ignore + else + sb.Append(c) |> ignore + authors.Add(sb.ToString()) + authors + + static member composeAuthors (authors : string) : ResizeArray = + ScholarlyArticleConversion.splitAuthors authors + |> Seq.map ScholarlyArticleConversion.composeAuthor + |> ResizeArray + + static member decomposeAuthor (author : LDNode, ?context : LDContext) : string = + let hasOnlyGivenName = + author.GetPropertyNames(?context = context) + |> Seq.filter(fun n -> n <> Person.givenName) + |> Seq.isEmpty + if hasOnlyGivenName then + Person.getGivenNameAsString(author, ?context = context) + else + Json.LDNode.encoder author + |> ARCtrl.Json.Encode.toJsonString 0 + + static member decomposeAuthors (authors : ResizeArray, ?context : LDContext) : string = + authors + |> ResizeArray.map (fun a -> ScholarlyArticleConversion.decomposeAuthor (a,?context = context)) + |> String.concat "," + + static member composeScholarlyArticle (publication : Publication) = + let title = match publication.Title with | Some t -> t | None -> failwith "Publication must have a title" + let authors = + publication.Authors + |> Option.map ScholarlyArticleConversion.composeAuthors + let comments = + publication.Comments + |> ResizeArray.map (BaseTypes.composeComment) + |> Option.fromSeq + let identifiers = ResizeArray [ + if publication.DOI.IsSome && publication.DOI.Value <> "" then + ScholarlyArticleConversion.composeDOI publication.DOI.Value + if publication.PubMedID.IsSome && publication.PubMedID.Value <> "" then + ScholarlyArticleConversion.composePubMedID publication.PubMedID.Value + ] + let status = publication.Status |> Option.map BaseTypes.composeDefinedTerm + let scholarlyArticle = + ScholarlyArticle.create( + headline = title, + identifiers = identifiers, + ?authors = authors, + //?url = publication.DOI, + ?creativeWorkStatus = status, + ?comments = comments + ) + scholarlyArticle + + static member decomposeScholarlyArticle (sa : LDNode, ?graph : LDGraph, ?context : LDContext) = + let title = ScholarlyArticle.getHeadlineAsString(sa, ?context = context) + let authors = + ScholarlyArticle.getAuthors(sa, ?graph = graph, ?context = context) + |> Option.fromSeq + |> Option.map (fun a -> ScholarlyArticleConversion.decomposeAuthors(a, ?context = context)) + let comments = + ScholarlyArticle.getComments(sa, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> BaseTypes.decomposeComment(c, ?context = context)) + let status = + ScholarlyArticle.tryGetCreativeWorkStatus(sa, ?graph = graph, ?context = context) + |> Option.map (fun s -> BaseTypes.decomposeDefinedTerm(s, ?context = context)) + let identifiers = ScholarlyArticle.getIdentifiersAsPropertyValue(sa, ?graph = graph, ?context = context) + let pubMedID = identifiers |> ResizeArray.tryPick (fun i -> ScholarlyArticleConversion.tryDecomposePubMedID(i, ?context = context)) + let doi = identifiers |> ResizeArray.tryPick (fun i -> ScholarlyArticleConversion.tryDecomposeDOI(i, ?context = context)) + ARCtrl.Publication.create( + title = title, + ?authors = authors, + ?status = status, + comments = comments, + ?doi = doi, + ?pubMedID = pubMedID + ) + +type AssayConversion = + + static member getDataFilesFromProcesses (processes : LDNode ResizeArray, ?graph : LDGraph, ?context : LDContext) = + let data = + processes + |> ResizeArray.collect (fun p -> + let inputs = LabProcess.getObjectsAsData(p, ?graph = graph, ?context = context) + let outputs = LabProcess.getResultsAsData(p, ?graph = graph, ?context = context) + ResizeArray.append inputs outputs + ) + |> ResizeArray.distinct + let files = + data + |> ResizeArray.filter (fun d -> + DataAux.pathAndSelectorFromName d.Id |> snd |> Option.isNone + ) + let filesFromfragments = + data + |> ResizeArray.filter (fun d -> + DataAux.pathAndSelectorFromName d.Id |> snd |> Option.isSome + ) + |> ResizeArray.groupBy (fun d -> + DataAux.pathAndSelectorFromName d.Id |> fst + ) + |> ResizeArray.map (fun (path,fragments) -> + let file = + match files |> ResizeArray.tryFind (fun d -> d.Id = path) with + | Some f -> f + | None -> + let comments = + File.getComments(fragments.[0], ?graph = graph, ?context = context) + |> Option.fromSeq + File.create( + id = path, + name = path, + ?comments = comments, + ?disambiguatingDescription = File.tryGetDisambiguatingDescriptionAsString(fragments.[0], ?context = context), + ?encodingFormat = File.tryGetEncodingFormatAsString(fragments.[0], ?context = context), + ?context = fragments.[0].TryGetContext() + ) + Dataset.setHasParts(file, fragments,?context = context) + file + ) + ResizeArray.append files filesFromfragments + + static member composeAssay (assay : ArcAssay) = + let measurementMethod = assay.TechnologyType |> Option.map BaseTypes.composeDefinedTerm + let measurementTechnique = assay.TechnologyPlatform |> Option.map BaseTypes.composeDefinedTerm + let variableMeasured = assay.MeasurementType |> Option.map BaseTypes.composePropertyValueFromOA + let creators = + assay.Performers + |> ResizeArray.map (fun c -> PersonConversion.composePerson c) + |> Option.fromSeq + let processSequence = + ArcTables(assay.Tables).GetProcesses() + |> ResizeArray + |> Option.fromSeq + let dataFiles = + processSequence + |> Option.map AssayConversion.getDataFilesFromProcesses + let comments = + assay.Comments + |> ResizeArray.map (fun c -> BaseTypes.composeComment c) + |> Option.fromSeq + Dataset.createAssay( + identifier = assay.Identifier, + ?description = None, // TODO + ?creators = creators, + ?hasParts = dataFiles, + ?measurementMethod = measurementMethod, + ?measurementTechnique = measurementTechnique, + ?variableMeasured = variableMeasured, + ?abouts = processSequence, + ?comments = comments + ) + + static member decomposeAssay (assay : LDNode, ?graph : LDGraph, ?context : LDContext) = + let measurementMethod = + Dataset.tryGetMeasurementMethodAsDefinedTerm(assay, ?graph = graph, ?context = context) + |> Option.map (fun m -> BaseTypes.decomposeDefinedTerm(m, ?context = context)) + let measurementTechnique = + Dataset.tryGetMeasurementTechniqueAsDefinedTerm(assay, ?graph = graph, ?context = context) + |> Option.map (fun m -> BaseTypes.decomposeDefinedTerm(m, ?context = context)) + let variableMeasured = + Dataset.tryGetVariableMeasuredAsPropertyValue(assay, ?graph = graph, ?context = context) + |> Option.map (fun v -> BaseTypes.decomposePropertyValueToOA(v, ?context = context)) + let perfomers = + Dataset.getCreators(assay, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> PersonConversion.decomposePerson(c, ?graph = graph, ?context = context)) + //let dataFiles = + // Assay.getHasParts(assay, ?graph = graph, ?context = context) + // |> Option.fromSeq + // |> Option.map (fun df -> BaseTypes.decomposeFile(df, ?graph = graph, ?context = context)) + let tables = + Dataset.getAboutsAsLabProcess(assay, ?graph = graph, ?context = context) + |> fun ps -> ArcTables.fromProcesses(List.ofSeq ps, ?graph = graph, ?context = context) + let comments = + Dataset.getComments(assay, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> BaseTypes.decomposeComment(c, ?context = context)) + ArcAssay.create( + identifier = Dataset.getIdentifierAsString(assay, ?context = context), + ?measurementType = variableMeasured, + ?technologyType = measurementMethod, + ?technologyPlatform = measurementTechnique, + tables = tables.Tables, + performers = perfomers, + comments = comments + ) + +type StudyConversion = + + static member composeStudy (study : ArcStudy) = + let dateCreated = study.SubmissionDate |> Option.bind DateTime.tryFromString + let datePublished = study.PublicReleaseDate |> Option.bind DateTime.tryFromString + let dateModified = System.DateTime.Now + let publications = + study.Publications + |> ResizeArray.map (fun p -> ScholarlyArticleConversion.composeScholarlyArticle p) + |> Option.fromSeq + let creators = + study.Contacts + |> ResizeArray.map (fun c -> PersonConversion.composePerson c) + |> Option.fromSeq + let processSequence = + ArcTables(study.Tables).GetProcesses() + |> ResizeArray + |> Option.fromSeq + let dataFiles = + processSequence + |> Option.map AssayConversion.getDataFilesFromProcesses + let comments = + study.Comments + |> ResizeArray.map (fun c -> BaseTypes.composeComment c) + |> Option.fromSeq + Dataset.createStudy( + identifier = study.Identifier, + ?name = study.Title, + ?description = study.Description, + ?dateCreated = dateCreated, + ?datePublished = datePublished, + dateModified = dateModified, + ?creators = creators, + ?citations = publications, + ?hasParts = dataFiles, + ?abouts = processSequence, + ?comments = comments + ) + + static member decomposeStudy (study : LDNode, ?graph : LDGraph, ?context : LDContext) = + let dateCreated = + Dataset.tryGetDateCreatedAsDateTime(study, ?context = context) + |> Option.map DateTime.toString + let datePublished = + Dataset.tryGetDatePublishedAsDateTime(study, ?context = context) + |> Option.map DateTime.toString + let publications = + Dataset.getCitations(study, ?graph = graph, ?context = context) + |> ResizeArray.map (fun p -> ScholarlyArticleConversion.decomposeScholarlyArticle(p, ?graph = graph, ?context = context)) + let creators = + Dataset.getCreators(study, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> PersonConversion.decomposePerson(c, ?graph = graph, ?context = context)) + //let dataFiles = + // Study.getHasParts(study, ?graph = graph, ?context = context) + // |> Option.fromSeq + // |> Option.map (fun df -> BaseTypes.decomposeFile(df, ?graph = graph, ?context = context)) + let tables = + Dataset.getAboutsAsLabProcess(study, ?graph = graph, ?context = context) + |> fun ps -> ArcTables.fromProcesses(List.ofSeq ps, ?graph = graph, ?context = context) + let comments = + Dataset.getComments(study, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> BaseTypes.decomposeComment(c, ?context = context)) + ArcStudy.create( + identifier = Dataset.getIdentifierAsString(study, ?context = context), + ?title = Dataset.tryGetNameAsString(study, ?context = context), + ?description = Dataset.tryGetDescriptionAsString(study, ?context = context), + ?submissionDate = dateCreated, + ?publicReleaseDate = datePublished, + contacts = creators, + publications = publications, + tables = tables.Tables, + comments = comments + ) + +type InvestigationConversion = + + static member composeInvestigation (investigation : ArcInvestigation) = + let name = match investigation.Title with | Some t -> t | None -> failwith "Investigation must have a title" + let dateCreated = investigation.SubmissionDate |> Option.bind DateTime.tryFromString + let datePublished = + investigation.PublicReleaseDate + |> Option.bind DateTime.tryFromString + |> Option.defaultValue (System.DateTime.Now) + //let dateModified = System.DateTime.Now + let publications = + investigation.Publications + |> ResizeArray.map (fun p -> ScholarlyArticleConversion.composeScholarlyArticle p) + |> Option.fromSeq + let creators = + investigation.Contacts + |> ResizeArray.map (fun c -> PersonConversion.composePerson c) + |> Option.fromSeq + let comments = + investigation.Comments + |> ResizeArray.map (fun c -> BaseTypes.composeComment c) + |> Option.fromSeq + let hasParts = + investigation.Assays + |> ResizeArray.map (fun a -> AssayConversion.composeAssay a) + |> ResizeArray.append (investigation.Studies |> ResizeArray.map (fun s -> StudyConversion.composeStudy s)) + |> Option.fromSeq + let mentions = + ResizeArray [] // TODO + |> Option.fromSeq + Dataset.createInvestigation( + identifier = investigation.Identifier, + name = name, + ?description = investigation.Description, + ?dateCreated = dateCreated, + datePublished = datePublished, + //dateModified = dateModified, + ?creators = creators, + ?citations = publications, + ?hasParts = hasParts, + ?mentions = mentions, + ?comments = comments + ) + + static member decomposeInvestigation (investigation : LDNode, ?graph : LDGraph, ?context : LDContext) = + let title = + match Dataset.tryGetNameAsString(investigation, ?context = context) with + | Some t -> Some t + | None -> Dataset.tryGetHeadlineAsString(investigation, ?context = context) + let dateCreated = + Dataset.tryGetDateCreatedAsDateTime(investigation, ?context = context) + |> Option.map DateTime.toString + let datePublished = + Dataset.tryGetDatePublishedAsDateTime(investigation, ?context = context) + |> Option.map DateTime.toString + let publications = + Dataset.getCitations(investigation, ?graph = graph, ?context = context) + |> ResizeArray.map (fun p -> ScholarlyArticleConversion.decomposeScholarlyArticle(p, ?graph = graph, ?context = context)) + let creators = + Dataset.getCreators(investigation, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> PersonConversion.decomposePerson(c, ?graph = graph, ?context = context)) + let datasets = + Dataset.getHasPartsAsDataset (investigation, ?graph = graph, ?context = context) + let studies = + datasets + |> ResizeArray.filter (fun d -> Dataset.validateStudy(d, ?context = context)) + |> ResizeArray.map (fun d -> StudyConversion.decomposeStudy(d, ?graph = graph, ?context = context)) + let assays = + datasets + |> ResizeArray.filter (fun d -> Dataset.validateAssay(d, ?context = context)) + |> ResizeArray.map (fun d -> AssayConversion.decomposeAssay(d, ?graph = graph, ?context = context)) + let comments = + Dataset.getComments(investigation, ?graph = graph, ?context = context) + |> ResizeArray.map (fun c -> BaseTypes.decomposeComment(c, ?context = context)) + ArcInvestigation.create( + identifier = Dataset.getIdentifierAsString(investigation, ?context = context), + ?title = title, + ?description = Dataset.tryGetDescriptionAsString(investigation, ?context = context), + ?submissionDate = dateCreated, + ?publicReleaseDate = datePublished, + contacts = creators, + publications = publications, + studies = studies, + assays = assays, + comments = comments + ) + +[] +module TypeExtensions = + + type ArcAssay with + member this.ToROCrateAssay() = AssayConversion.composeAssay this + + static member fromROCrateAssay (a : LDNode, ?graph : LDGraph, ?context : LDContext) = AssayConversion.decomposeAssay(a, ?graph = graph, ?context = context) + + type ArcStudy with + member this.ToROCrateStudy() = StudyConversion.composeStudy this + + static member fromROCrateStudy (a : LDNode, ?graph : LDGraph, ?context : LDContext) = StudyConversion.decomposeStudy(a, ?graph = graph, ?context = context) + + type ArcInvestigation with + member this.ToROCrateInvestigation() = InvestigationConversion.composeInvestigation this + + static member fromROCrateInvestigation (a : LDNode, ?graph : LDGraph, ?context : LDContext) = InvestigationConversion.decomposeInvestigation(a, ?graph = graph, ?context = context) + + type Dataset with + static member toArcAssay(a : LDNode, ?graph : LDGraph, ?context : LDContext) = AssayConversion.decomposeAssay(a, ?graph = graph, ?context = context) + + static member fromArcAssay (a : ArcAssay) = AssayConversion.composeAssay a + + static member toArcStudy(a : LDNode, ?graph : LDGraph, ?context : LDContext) = StudyConversion.decomposeStudy(a, ?graph = graph, ?context = context) + + static member fromArcStudy (a : ArcStudy) = StudyConversion.composeStudy a + + static member toArcInvestigation(a : LDNode, ?graph : LDGraph, ?context : LDContext) = InvestigationConversion.decomposeInvestigation(a, ?graph = graph, ?context = context) + + static member fromArcInvestigation (a : ArcInvestigation) = InvestigationConversion.composeInvestigation a + diff --git a/src/ARCtrl/JsonIO/ARC.fs b/src/ARCtrl/JsonIO/ARC.fs deleted file mode 100644 index a129ec8c..00000000 --- a/src/ARCtrl/JsonIO/ARC.fs +++ /dev/null @@ -1,30 +0,0 @@ -namespace ARCtrl.Json - -open Thoth.Json.Core - -open ARCtrl -open ARCtrl.Helper - -module ARC = - - /// Functions for serializing and deserializing ARC objects to RO-Crate Root Data Entity - /// - /// See https://www.researchobject.org/ro-crate/1.1/root-data-entity.html for more information - module ROCrate = - - let encoder (isa : ArcInvestigation) = - [ - Encode.tryInclude "@type" Encode.string (Some "CreativeWork") - Encode.tryInclude "@id" Encode.string (Some "ro-crate-metadata.json") - Encode.tryInclude "about" Investigation.ROCrate.encoder (Some isa) - "conformsTo", ROCrateContext.ROCrate.conformsTo_jsonvalue |> Some - "@context", ROCrateContext.ROCrate.context_jsonvalue |> Some - ] - |> Encode.choose - |> Encode.object - - let decoder : Decoder = - Decode.object (fun get -> - let isa = get.Optional.Field "about" Investigation.ROCrate.decoder - isa - ) \ No newline at end of file diff --git a/src/ARCtrl/JsonIO/LDObject.fs b/src/ARCtrl/JsonIO/LDObject.fs index 1a4fe343..7d909f6b 100644 --- a/src/ARCtrl/JsonIO/LDObject.fs +++ b/src/ARCtrl/JsonIO/LDObject.fs @@ -8,18 +8,35 @@ open Thoth.Json.Core open DynamicObj [] -module LDObjectExtensions = +module LDNodeExtensions = - type LDObject with + type LDNode with static member fromROCrateJsonString (s:string) = - Decode.fromJsonString LDObject.decoder s + Decode.fromJsonString LDNode.decoder s /// exports in json-ld format static member toROCrateJsonString(?spaces) = - fun (obj:LDObject) -> - LDObject.encoder obj + fun (obj:LDNode) -> + LDNode.encoder obj |> Encode.toJsonString (Encode.defaultSpaces spaces) member this.ToROCrateJsonString(?spaces) = - LDObject.toROCrateJsonString(?spaces=spaces) this \ No newline at end of file + LDNode.toROCrateJsonString(?spaces=spaces) this + +[] +module LDGraphExtensions = + + type LDGraph with + + static member fromROCrateJsonString (s:string) = + Decode.fromJsonString LDGraph.decoder s + + /// exports in json-ld format + static member toROCrateJsonString(?spaces) = + fun (obj:LDGraph) -> + LDGraph.encoder obj + |> Encode.toJsonString (Encode.defaultSpaces spaces) + + member this.ToROCrateJsonString(?spaces) = + LDGraph.toROCrateJsonString(?spaces=spaces) this \ No newline at end of file diff --git a/src/ARCtrl/ROCrateIO.fs b/src/ARCtrl/ROCrateIO.fs new file mode 100644 index 00000000..d9250993 --- /dev/null +++ b/src/ARCtrl/ROCrateIO.fs @@ -0,0 +1,63 @@ +namespace ARCtrl.Json + +open Thoth.Json.Core + +open ARCtrl +open ARCtrl.ROCrate +open ARCtrl.Helper +open ARCtrl.Conversion + +module ARC = + + /// Functions for serializing and deserializing ARC objects to RO-Crate Root Data Entity + /// + /// See https://www.researchobject.org/ro-crate/1.1/root-data-entity.html for more information + type ROCrate = + + static member getDefaultLicense() = + //let cw = LDNode("License", ResizeArray ["https://schema.org/CreativeWork"]) + //cw.SetProperty("https://schema.org/name", "ALL RIGHTS RESERVED BY THE AUTHORS") + //cw.SetProperty("https://schema.org/about",LDRef "./") + //cw + "ALL RIGHTS RESERVED BY THE AUTHORS" + + static member metadataFileDescriptor = + let id = "ro-crate-metadata.json" + let schemaType = ResizeArray ["http://schema.org/CreativeWork"] + let node = LDNode(id, schemaType) + node.SetProperty("http://purl.org/dc/terms/conformsTo", LDRef("https://w3id.org/ro/crate/1.1")) + node.SetProperty("http://schema.org/about", LDRef("./")) + node + + static member encoder (isa : ArcInvestigation, ?license : obj) = + let license = match license with + | Some license -> license + | None -> ROCrate.getDefaultLicense() + let isa = isa.ToROCrateInvestigation() + Dataset.setSDDatePublishedAsDateTime(isa, System.DateTime.Now) + Dataset.setLicenseAsCreativeWork(isa, license) + let graph = isa.Flatten() + let context = LDContext(baseContexts=ResizeArray[Context.initV1_1();Context.initBioschemasContext()]) + graph.SetContext(context) + graph.AddNode(ROCrate.metadataFileDescriptor) + graph.Compact_InPlace() + LDGraph.encoder graph + + static member decoder : Decoder = + LDGraph.decoder + |> Decode.map (fun graph -> + match graph.TryGetNode("./") with + | Some node -> + ArcInvestigation.fromROCrateInvestigation(node, graph = graph, ?context = graph.TryGetContext()) + | None -> + failwith "RO-Crate graph did not contain root data Entity" + ) + + static member decoderDeprecated : Decoder = + LDNode.decoder + |> Decode.map (fun ldnode -> + ldnode + |> Dataset.getAbouts + |> Seq.exactlyOne + |> ArcInvestigation.fromROCrateInvestigation + ) \ No newline at end of file diff --git a/src/Core/ARCtrl.Core.fsproj b/src/Core/ARCtrl.Core.fsproj index 942a2114..6bae06bb 100644 --- a/src/Core/ARCtrl.Core.fsproj +++ b/src/Core/ARCtrl.Core.fsproj @@ -9,8 +9,10 @@ + + diff --git a/src/Core/Data.fs b/src/Core/Data.fs index 5c028f45..66317bdf 100644 --- a/src/Core/Data.fs +++ b/src/Core/Data.fs @@ -10,6 +10,7 @@ module DataAux = sprintf "%s#%s" path selector let pathAndSelectorFromName (name : string) = + let name = name.Trim('#') let parts = name.Split('#') if parts.Length = 2 then parts.[0], Some parts.[1] @@ -88,6 +89,28 @@ type Data(?id,?name : string,?dataType,?format,?selectorFormat,?comments) = this.Name |> Option.defaultValue "" + member this.GetAbsolutePathForAssay(assayIdentifier : string, ?checkExistenceFromRoot : string -> bool) = + let folderPath = $"assays/{assayIdentifier}/dataset/" + let checkExistenceFromRoot = Option.defaultValue (fun _ -> false) checkExistenceFromRoot + match this.FilePath with + | Some p -> + if checkExistenceFromRoot p || p.StartsWith("assays/") || p.StartsWith("studies/") || p.StartsWith("http:") || p.StartsWith("https:") then + p + else + folderPath + p.TrimStart('/') + | None -> failwith "Data does not have a file path" + + member this.GetAbsolutePathForStudy(studyIdentifier : string, ?checkExistenceFromRoot : string -> bool) = + let folderPath = $"studies/{studyIdentifier}/resources/" + let checkExistenceFromRoot = Option.defaultValue (fun _ -> false) checkExistenceFromRoot + match this.FilePath with + | Some p -> + if checkExistenceFromRoot p || p.StartsWith("assays/") || p.StartsWith("studies/") || p.StartsWith("http:") || p.StartsWith("https:") then + p + else + folderPath + p.TrimStart('/') + | None -> failwith "Data does not have a file path" + member this.Copy() = let nextComments = this.Comments |> ResizeArray.map (fun c -> c.Copy()) Data(?id=this.ID,?name=this.Name,?dataType=this.DataType,?format=this.Format,?selectorFormat=this.SelectorFormat,comments=nextComments) diff --git a/src/Core/DataFile.fs b/src/Core/DataFile.fs index b8c3ecef..6c23b72f 100644 --- a/src/Core/DataFile.fs +++ b/src/Core/DataFile.fs @@ -1,4 +1,4 @@ -namespace ARCtrl +namespace ARCtrl open ARCtrl @@ -15,9 +15,16 @@ type DataFile = member this.AsString = match this with - | RawDataFile -> "RawDataFileJson" - | DerivedDataFile -> "DerivedDataFileJson" - | ImageFile -> "ImageFileJson" + | RawDataFile -> "Raw Data File" + | DerivedDataFile -> "Derived Data File" + | ImageFile -> "Image File" + + static member fromString (dt : string) = + match dt with + | "RawDataFileJson" | "Raw Data File" -> RawDataFile + | "DerivedDataFileJson" | "Derived Data File" -> DerivedDataFile + | "ImageFileJson" | "Image File" -> ImageFile + | _ -> failwith $"Invalid DataFile type: {dt}" member this.IsDerivedData = match this with diff --git a/src/Core/Helper/Collections.fs b/src/Core/Helper/Collections.fs index ce094bc9..0c738410 100644 --- a/src/Core/Helper/Collections.fs +++ b/src/Core/Helper/Collections.fs @@ -1,4 +1,4 @@ -namespace ARCtrl.Helper +namespace ARCtrl.Helper module Seq = let inline compare (a: seq<'a>) (b: seq<'a>) = @@ -28,6 +28,11 @@ module Option = | Some v -> Some (f v) | None -> d + /// If the value matches the default, a None is returned, else a Some is returned + let fromSeq (v : 'T when 'T :> System.Collections.IEnumerable) = + if Seq.isEmpty v then None + else Some v + module internal List = let tryPickAndRemove (f : 'T -> 'U option) (lst : 'T list) = @@ -44,6 +49,12 @@ module Dictionary = open System.Collections.Generic + let addOrUpdate (key : 'Key) (value : 'T) (dict : Dictionary<'Key,'T>) = + if dict.ContainsKey key then + dict.[key] <- value + else + dict.Add(key,value) + let ofSeq (s : seq<'Key*'T>) = let dict = Dictionary() s @@ -79,6 +90,20 @@ module Dictionary = module ResizeArray = + open System.Collections.Generic + + let create (i : int) (v : 'T) = + let a = ResizeArray<_>() + if i > 0 then + for _ in 1 .. i do + a.Add(v) + a + + let singleton (a : 'T) = + let b = ResizeArray<_>() + b.Add(a) + b + let map f (a : ResizeArray<_>) = let b = ResizeArray<_>() for i in a do @@ -158,4 +183,37 @@ module ResizeArray = for i in a do c.Add(i) c.Add(b) - c \ No newline at end of file + c + + + // Make sure that output type matches + let groupBy (f : 'T -> 'a) (a : ResizeArray<'T>) : ResizeArray<'a*ResizeArray<'T>> = + Seq.groupBy f a + |> Seq.map (fun (k,v) -> k, ResizeArray v) + |> ResizeArray + + let tryPick f (a : ResizeArray<'T>) = + let rec loop i = + if i < a.Count then + match f a.[i] with + | Some v -> Some v + | None -> loop (i + 1) + else None + loop 0 + + let zip (a : ResizeArray<'T>) (b : ResizeArray<'U>) = + let c = ResizeArray<_>() + let n = min a.Count b.Count + for i in 0 .. n - 1 do + c.Add(a.[i], b.[i]) + c + + let tryFind f (a : ResizeArray<'T>) = + let rec loop i = + if i < a.Count then + if f a.[i] then + Some a.[i] + else + loop (i + 1) + else None + loop 0 \ No newline at end of file diff --git a/src/Core/Helper/DateTime.fs b/src/Core/Helper/DateTime.fs new file mode 100644 index 00000000..ccfb5ecd --- /dev/null +++ b/src/Core/Helper/DateTime.fs @@ -0,0 +1,6 @@ +module ARCtrl.Helper.DateTime + +let tryParse (s : string) = + match System.DateTime.TryParse(s) with + | true, datetime -> Some datetime + | _ -> None diff --git a/src/Core/Helper/ORCID.fs b/src/Core/Helper/ORCID.fs new file mode 100644 index 00000000..118df022 --- /dev/null +++ b/src/Core/Helper/ORCID.fs @@ -0,0 +1,27 @@ +module ARCtrl.Helper.ORCID + +open ARCtrl.Helper.Regex.ActivePatterns + +[] +let orcidPattern = @"[0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{3}[0-9X]" + +let orcidRegex = System.Text.RegularExpressions.Regex(orcidPattern) + +let tryGetOrcidNumber (orcid : string) = + let m = orcidRegex.Match(orcid) + if m.Success then + Some m.Value + else + None + +let orcidPrefix = "http://orcid.org/" + +let (|ORCID|_|) input = + match input with + | Regex orcidPattern r -> Some r + | _ -> None + +let tryGetOrcidURL (orcid : string) = + match orcid with + | ORCID orcid -> Some $"{orcidPrefix}{orcid}" + | _ -> None \ No newline at end of file diff --git a/src/Json/ARC.fs b/src/Json/ARC.fs deleted file mode 100644 index a129ec8c..00000000 --- a/src/Json/ARC.fs +++ /dev/null @@ -1,30 +0,0 @@ -namespace ARCtrl.Json - -open Thoth.Json.Core - -open ARCtrl -open ARCtrl.Helper - -module ARC = - - /// Functions for serializing and deserializing ARC objects to RO-Crate Root Data Entity - /// - /// See https://www.researchobject.org/ro-crate/1.1/root-data-entity.html for more information - module ROCrate = - - let encoder (isa : ArcInvestigation) = - [ - Encode.tryInclude "@type" Encode.string (Some "CreativeWork") - Encode.tryInclude "@id" Encode.string (Some "ro-crate-metadata.json") - Encode.tryInclude "about" Investigation.ROCrate.encoder (Some isa) - "conformsTo", ROCrateContext.ROCrate.conformsTo_jsonvalue |> Some - "@context", ROCrateContext.ROCrate.context_jsonvalue |> Some - ] - |> Encode.choose - |> Encode.object - - let decoder : Decoder = - Decode.object (fun get -> - let isa = get.Optional.Field "about" Investigation.ROCrate.decoder - isa - ) \ No newline at end of file diff --git a/src/Json/ARCtrl.Json.fsproj b/src/Json/ARCtrl.Json.fsproj index 64095531..cd657d89 100644 --- a/src/Json/ARCtrl.Json.fsproj +++ b/src/Json/ARCtrl.Json.fsproj @@ -35,6 +35,11 @@ + + + + + @@ -75,8 +80,6 @@ - - diff --git a/src/Json/Decode.fs b/src/Json/Decode.fs index a52231f0..720991d0 100644 --- a/src/Json/Decode.fs +++ b/src/Json/Decode.fs @@ -93,9 +93,7 @@ module Decode = decoder.Decode(helpers,value) } - - - let resizeArray (decoder: Decoder<'value>) : Decoder> = + let resizeArrayOrSingleton (decoder: Decoder<'value>) : Decoder> = { new Decoder> with member _.Decode(helpers, value) = if helpers.isArray value then @@ -123,7 +121,7 @@ module Decode = Ok acc ) else - ("", BadPrimitive("an array", value)) |> Error + decoder.Decode(helpers, value) |> Result.map (fun x -> ResizeArray[x]) } let datetime: Decoder = diff --git a/src/Json/Encode.fs b/src/Json/Encode.fs index fabebd65..58c9932c 100644 --- a/src/Json/Encode.fs +++ b/src/Json/Encode.fs @@ -63,4 +63,12 @@ module Encode = let addPropertyToObject (name : string) (value : Json) (obj : Json) = match obj with | Json.Object kvs -> Json.Object (Seq.append kvs [name, value] ) - | _ -> failwith "Expected object" \ No newline at end of file + | _ -> failwith "Expected object" + + let resizeArrayOrSingleton (encoder : 'T -> IEncodable) (values: ResizeArray<'T>) = + if values.Count = 1 then + values.[0] |> encoder + else + values + |> Seq.map encoder + |> Encode.seq \ No newline at end of file diff --git a/src/Json/ROCrate/LDContext.fs b/src/Json/ROCrate/LDContext.fs new file mode 100644 index 00000000..3b1aa8aa --- /dev/null +++ b/src/Json/ROCrate/LDContext.fs @@ -0,0 +1,64 @@ +namespace ARCtrl.Json + +open ARCtrl +open System +open ARCtrl.ROCrate +open Thoth.Json.Core +open DynamicObj + +module LDContext = + + let decoder : Decoder = + { new Decoder with + member this.Decode(helpers, value) = + if helpers.isObject value then + let getters = Decode.Getters(helpers, value) + let properties = helpers.getProperties value + let builder = + fun (get : Decode.IGetters) -> + let o = LDContext() + for property in properties do + if property <> "@id" && property <> "@type" then + o.AddMapping(property,get.Required.Field property Decode.string) + o + let result = builder getters + match getters.Errors with + | [] -> Ok result + | fst :: _ as errors -> + if errors.Length > 1 then + ("", BadOneOf errors) |> Error + else + Error fst + elif helpers.isString value then + let s = helpers.asString value + if s = Context.proxy_V1_2DRAFT then + Ok (Context.initV1_2DRAFT()) + elif s = Context.proxy_V1_1 then + Ok (Context.initV1_1()) + else + ("", BadPrimitive("an object", value)) |> Error + elif helpers.isArray value then + match Decode.resizeArray(this).Decode(helpers,value) with + | Ok baseContexts -> Ok (LDContext(baseContexts = baseContexts)) + | Error e -> Error e + else + ("", BadPrimitive("an object", value)) |> Error + } + + let rec encoder (ctx: LDContext) = + match ctx.Name with + | Some Context.proxy_V1_2DRAFT -> Encode.string Context.proxy_V1_2DRAFT + | Some Context.proxy_V1_1 -> Encode.string Context.proxy_V1_1 + | _ -> + let mappings = + ctx.Mappings + |> Seq.map (fun kv -> kv.Key, kv.Value |> string |> Encode.string ) + |> Encode.object + if ctx.BaseContexts.Count = 0 then + mappings + elif ctx.BaseContexts.Count = 1 && ctx.Mappings.Count = 0 then + ctx.BaseContexts.[0] |> encoder + else + ctx.BaseContexts |> Seq.map encoder + |> Seq.append [ if ctx.Mappings.Count <> 0 then mappings ] + |> Encode.seq \ No newline at end of file diff --git a/src/Json/ROCrate/LDGraph.fs b/src/Json/ROCrate/LDGraph.fs new file mode 100644 index 00000000..08b53cae --- /dev/null +++ b/src/Json/ROCrate/LDGraph.fs @@ -0,0 +1,56 @@ +namespace ARCtrl.Json + +open ARCtrl +open System +open ARCtrl.ROCrate +open Thoth.Json.Core +open DynamicObj + + +module rec LDGraph = + + let encoder(obj: LDGraph) = + + [ + Encode.tryInclude "@id" Encode.string obj.Id + Encode.tryInclude "@context" LDContext.encoder (obj.TryGetContext()) + for kv in (obj.GetProperties true) do + let l = kv.Key.ToLower() + if l <> "id" && l <> "@context" && l <> "nodes" && l <> "mappings" then + kv.Key, Some (LDNode.genericEncoder kv.Value) + "@graph", obj.Nodes |> Seq.map LDNode.encoder |> Encode.seq |> Some + ] + |> Encode.choose + |> Encode.object + + + let decoder : Decoder = + { new Decoder with + member _.Decode(helpers, value) = + if helpers.isObject value then + let getters = Decode.Getters(helpers, value) + let properties = helpers.getProperties value + let builder = + fun (get : Decode.IGetters) -> + let id = get.Optional.Field "@id" Decode.string + let context = get.Optional.Field "@context" LDContext.decoder + let nodes = get.Required.Field "@graph" (Decode.seq LDNode.decoder) + let o = LDGraph(?id = id, ?context = context) + for property in properties do + if property <> "@id" && property <> "@graph" && property <> "@context" then + o.SetProperty(property,get.Required.Field property LDNode.genericDecoder) + for node in nodes do + o.AddNode node + o + let result = builder getters + match getters.Errors with + | [] -> Ok result + | fst :: _ as errors -> + if errors.Length > 1 then + ("", BadOneOf errors) |> Error + else + Error fst + else ("", BadPrimitive("an object", value)) |> Error + + } + diff --git a/src/Json/LDObject.fs b/src/Json/ROCrate/LDNode.fs similarity index 67% rename from src/Json/LDObject.fs rename to src/Json/ROCrate/LDNode.fs index a9aae98c..888e58e4 100644 --- a/src/Json/LDObject.fs +++ b/src/Json/ROCrate/LDNode.fs @@ -6,8 +6,8 @@ open ARCtrl.ROCrate open Thoth.Json.Core open DynamicObj -module rec LDObject = +module rec LDNode = #if !FABLE_COMPILER let (|SomeObj|_|) = // create generalized option type @@ -36,7 +36,9 @@ module rec LDObject = | :? bool as b -> Encode.bool b | :? float as f -> Encode.float f | :? DateTime as d -> Encode.dateTime d - | :? LDObject as o -> encoder o + | :? LDValue as v -> LDValue.encoder v + | :? LDRef as r -> LDRef.encoder r + | :? LDNode as o -> encoder o #if !FABLE_COMPILER | SomeObj o -> genericEncoder o #endif @@ -44,21 +46,37 @@ module rec LDObject = | :? System.Collections.IEnumerable as l -> [ for x in l -> genericEncoder x] |> Encode.list | _ -> failwith "Unknown type" - let rec encoder(obj: LDObject) = - obj.GetProperties true - |> Seq.choose (fun kv -> - let l = kv.Key.ToLower() - if l <> "id" && l <> "schematype" && l <> "additionaltype" then - Some(kv.Key, genericEncoder kv.Value) - else - None + let rec encoder(obj: LDNode) = + //obj.GetProperties true + //|> Seq.choose (fun kv -> + // let l = kv.Key.ToLower() + // if l <> "id" && l <> "schematype" && l <> "additionaltype" && l <> "@context" then + // Some(kv.Key, genericEncoder kv.Value) + // else + // None - ) - |> Seq.append [ - "@id", Encode.string obj.Id - "@type", Encode.string obj.SchemaType - if obj.AdditionalType.IsSome then - "additionalType", Encode.string obj.AdditionalType.Value + //) + //|> Seq.append [ + // "@id", Encode.string obj.Id + // "@type", LDType.encoder obj.SchemaType + // if obj.AdditionalType.IsSome then + // "additionalType", Encode.string obj.AdditionalType.Value + // match obj.TryGetContext() with + // | Some ctx -> "@context", LDContext.encoder ctx + // | _ -> () + //] + [ + yield "@id", Encode.string obj.Id + yield "@type", Encode.resizeArrayOrSingleton Encode.string obj.SchemaType + if obj.AdditionalType.Count <> 0 then + yield "additionalType", Encode.resizeArrayOrSingleton Encode.string obj.AdditionalType + match obj.TryGetContext() with + | Some ctx -> yield "@context", LDContext.encoder ctx + | _ -> () + for kv in (obj.GetProperties true) do + let l = kv.Key.ToLower() + if l <> "id" && l <> "schematype" && l <> "additionaltype" && l <> "@context" && (l.StartsWith("init@") |> not) && (l.StartsWith("init_") |> not)then + yield kv.Key, genericEncoder kv.Value ] |> Encode.object @@ -67,20 +85,23 @@ module rec LDObject = /// If expectObject is set to true, decoder fails if top-level value is not an ROCrate object let rec getDecoder (expectObject : bool) : Decoder = let rec decode(expectObject) = - let decodeObject : Decoder = - { new Decoder with + let decodeObject : Decoder = + { new Decoder with member _.Decode(helpers, value) = if helpers.isObject value then let getters = Decode.Getters(helpers, value) let properties = helpers.getProperties value let builder = fun (get : Decode.IGetters) -> - let t = get.Required.Field "@type" Decode.string + let t = get.Required.Field "@type" (Decode.resizeArrayOrSingleton Decode.string) let id = get.Required.Field "@id" Decode.string - let o = LDObject(id,t) + let context = get.Optional.Field "@context" LDContext.decoder + let at = get.Optional.Field "additionalType" (Decode.resizeArrayOrSingleton Decode.string) + let o = LDNode(id, t, ?additionalType = at) for property in properties do - if property <> "@id" && property <> "@type" then + if property <> "@id" && property <> "@type" && property <> "@context" then o.SetProperty(property,get.Required.Field property (decode(false))) + if context.IsSome then o.SetContext context.Value o let result = builder getters match getters.Errors with @@ -127,15 +148,16 @@ module rec LDObject = Decode.map box (decodeObject) else Decode.oneOf [ + Decode.map box (LDValue.decoder) Decode.map box (decodeObject) + Decode.map box (LDRef.decoder) Decode.map box (resizeArray) Decode.map box (Decode.string) Decode.map box (Decode.int) Decode.map box (Decode.decimal) - ] decode(expectObject) - let decoder : Decoder = Decode.map unbox (getDecoder(true)) + let decoder : Decoder = Decode.map unbox (getDecoder(true)) let genericDecoder : Decoder = getDecoder(false) diff --git a/src/Json/ROCrate/LDRef.fs b/src/Json/ROCrate/LDRef.fs new file mode 100644 index 00000000..db849adf --- /dev/null +++ b/src/Json/ROCrate/LDRef.fs @@ -0,0 +1,22 @@ +namespace ARCtrl.Json + +open ARCtrl +open System +open ARCtrl.ROCrate +open Thoth.Json.Core +open DynamicObj + +module LDRef = + + let decoder : Decoder = + Decode.object (fun decoders -> + let id = decoders.Required.Field "@id" Decode.string + LDRef(id) + ) + + let encoder (r: LDRef) = + [ + "@id", Encode.string r.Id + ] + |> Encode.object + diff --git a/src/Json/ROCrate/LDValue.fs b/src/Json/ROCrate/LDValue.fs new file mode 100644 index 00000000..b0026092 --- /dev/null +++ b/src/Json/ROCrate/LDValue.fs @@ -0,0 +1,39 @@ +namespace ARCtrl.Json + +open ARCtrl +open System +open ARCtrl.ROCrate +open Thoth.Json.Core +open DynamicObj + +module LDValue = + + let genericDecoder = + Decode.oneOf [ + Decode.map box Decode.string + Decode.map box Decode.int + Decode.map box Decode.decimal + ] + + let genericEncoder (value : obj) = + match value with + | :? string as s -> Encode.string s + | :? int as i -> Encode.int i + | :? bool as b -> Encode.bool b + | :? float as f -> Encode.float f + | :? DateTime as d -> Encode.dateTime d + | _ -> failwith "Unknown type" + + let decoder : Decoder = + Decode.object (fun decoders -> + let value = decoders.Required.Field "@value" genericDecoder + let valueType = decoders.Optional.Field "@type" Decode.string + LDValue(value, ?valueType = valueType) + ) + + let encoder (v: LDValue) = + [ + "@value", genericEncoder v.Value + "@type", Encode.string v.ValueType + ] + |> Encode.object diff --git a/src/ROCrate/ARCtrl.ROCrate.fsproj b/src/ROCrate/ARCtrl.ROCrate.fsproj index e5dfc51f..60833990 100644 --- a/src/ROCrate/ARCtrl.ROCrate.fsproj +++ b/src/ROCrate/ARCtrl.ROCrate.fsproj @@ -7,19 +7,23 @@ + + + - - - - - - - - - - - + + + + + + + + + + + + @@ -27,4 +31,7 @@ + + + diff --git a/src/ROCrate/ArcROCrateMetadata.fs b/src/ROCrate/ArcROCrateMetadata.fs index 2fd930b1..23abcb0d 100644 --- a/src/ROCrate/ArcROCrateMetadata.fs +++ b/src/ROCrate/ArcROCrateMetadata.fs @@ -2,9 +2,9 @@ namespace ARCtrl.ROCrate open DynamicObj -type ArcROCrateMetadata(?about : LDObject) as this = +type ArcROCrateMetadata(?about : LDNode) as this = - inherit LDObject(id = "ro-crate-metadata",schemaType = "CreativeWork") + inherit LDNode(id = "ro-crate-metadata",schemaType = ResizeArray([|"CreativeWork"|])) do DynObj.setOptionalProperty (nameof about) about this @@ -15,10 +15,10 @@ type ArcROCrateMetadata(?about : LDObject) as this = do let context = LDContext() - context.SetProperty("sdo", "http://schema.org/") - context.SetProperty("arc", "http://purl.org/nfdi4plants/ontology/") - context.SetProperty("CreativeWork", "sdo:CreativeWork") - context.SetProperty("about", "sdo:about") - context.SetProperty("conformsTo", "sdo:conformsTo") + context.AddMapping("sdo", "http://schema.org/") + context.AddMapping("arc", "http://purl.org/nfdi4plants/ontology/") + context.AddMapping("CreativeWork", "sdo:CreativeWork") + context.AddMapping("about", "sdo:about") + context.AddMapping("conformsTo", "sdo:conformsTo") this.SetProperty("@context", context) diff --git a/src/ROCrate/DynObjExtensions.fs b/src/ROCrate/DynObjExtensions.fs index 1cb8fe70..a84d676f 100644 --- a/src/ROCrate/DynObjExtensions.fs +++ b/src/ROCrate/DynObjExtensions.fs @@ -12,4 +12,10 @@ module DynObj = | Some value -> value | None -> raise (System.InvalidCastException($"Property '{propertyName}' is set on this '{className}' object but cannot be cast to '{(typeof<'TPropertyValue>).Name}'")) else - raise (System.MissingMemberException($"No property '{propertyName}' set on this '{className}' object although it is mandatory. Was it created correctly?")) \ No newline at end of file + raise (System.MissingMemberException($"No property '{propertyName}' set on this '{className}' object although it is mandatory. Was it created correctly?")) + + let inline tryGetTypedPropertyValueAsResizeArray<'T> (name : string) (obj : DynamicObj) = + match obj.TryGetPropertyValue(name) with + | Some (:? ResizeArray<'T> as ra) -> Some ra + | Some (:? 'T as singleton) -> Some (ResizeArray [singleton]) + | _ -> None \ No newline at end of file diff --git a/src/ROCrate/Generic/Comment.fs b/src/ROCrate/Generic/Comment.fs new file mode 100644 index 00000000..818834bb --- /dev/null +++ b/src/ROCrate/Generic/Comment.fs @@ -0,0 +1,62 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +/// +[] +type Comment = + + static member schemaType = "http://schema.org/Comment" + + static member text = "http://schema.org/text" + + static member name = "http://schema.org/name" + + static member tryGetTextAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(Comment.text, ?context = context) with + | Some (:? string as tc) -> Some tc + | _ -> None + + static member getTextAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(Comment.text, ?context = context) with + | Some (:? string as tc) -> tc + | Some _ -> failwith $"Property of `text` of object with @id `{dt.Id}` was not a string" + | _ -> failwith $"Could not access property `text` of object with @id `{dt.Id}`" + + static member setTextAsString(dt : LDNode, text : string, ?context : LDContext) = + dt.SetProperty(Comment.text, text, ?context = context) + + static member tryGetNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(Comment.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(Comment.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `name` of object with @id `{dt.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{dt.Id}`" + + static member setNameAsString(dt : LDNode, name : string, ?context : LDContext) = + dt.SetProperty(Comment.name, name, ?context = context) + + static member genID(name : string, ?text : string) = + match text with + | Some t -> $"#Comment_{name}_{t}" + | None -> $"#Comment_{name}" + |> Helper.ID.clean + + static member validate(dt : LDNode, ?context : LDContext) = + dt.HasType(Comment.schemaType, ?context = context) + && dt.HasProperty(Comment.name, ?context = context) + + static member create(name : string, ?id : string, ?text : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Comment.genID(name, ?text = text) + let dt = LDNode(id, ResizeArray [Comment.schemaType], ?context = context) + dt.SetProperty(Comment.name, name, ?context = context) + dt.SetOptionalProperty(Comment.text, text, ?context = context) + dt \ No newline at end of file diff --git a/src/ROCrate/Generic/Dataset.fs b/src/ROCrate/Generic/Dataset.fs new file mode 100644 index 00000000..e86629f1 --- /dev/null +++ b/src/ROCrate/Generic/Dataset.fs @@ -0,0 +1,333 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate +open ARCtrl.Helper + +[] +type Dataset = + + static member schemaType = "http://schema.org/Dataset" + + static member additionalType = "http://schema.org/Dataset" + + static member identifier = "http://schema.org/identifier" + + static member creator = "http://schema.org/creator" + + static member dateCreated = "http://schema.org/dateCreated" + + static member datePublished = "http://schema.org/datePublished" + + static member sdDatePublished = "http://schema.org/datePublished" + + static member license = "http://schema.org/license" + + static member dateModified = "http://schema.org/dateModified" + + static member description = "http://schema.org/description" + + static member hasPart = "http://schema.org/hasPart" + + static member headline = "http://schema.org/headline" + + static member name = "http://schema.org/name" + + static member citation = "http://schema.org/citation" + + static member comment = "http://schema.org/comment" + + static member mentions = "http://schema.org/mentions" + + static member url = "http://schema.org/url" + + static member about = "http://schema.org/about" + + static member measurementMethod = "http://schema.org/measurementMethod" + + static member measurementTechnique = "http://schema.org/measurementTechnique" + + static member variableMeasured = "http://schema.org/variableMeasured" + + static member tryGetIdentifierAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.identifier, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getIdentifierAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.identifier, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"property `identifier` of object with @id `{lp.Id}` was not a string" + | _ -> failwith $"Could not access property `identifier` of object with @id `{lp.Id}`" + + static member setIdentifierAsString(lp : LDNode, identifier : string, ?context : LDContext) = + lp.SetProperty(Dataset.identifier, identifier, ?context = context) + + static member getCreators(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter (p : LDNode) (ctx : LDContext option) = Person.validate(p, ?context = ctx) + lp.GetPropertyNodes(Dataset.creator, filter = filter, ?graph = graph, ?context = context) + + //static member getCreatorsAsPerson(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + // let filter (p : LDNode) (ctx : LDContext option) = Person.validate(p, ?context = ctx) + // lp.GetPropertyNodes(Dataset.creator, filter = filter, ?graph = graph, ?context = context) + + static member setCreators(lp : LDNode, creators : ResizeArray, ?context : LDContext) = + lp.SetProperty(Dataset.creator, creators, ?context = context) + + static member tryGetDateCreatedAsDateTime(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.dateCreated, ?context = context) with + | Some (:? System.DateTime as n) -> Some n + | _ -> None + + static member setDateCreatedAsDateTime(lp : LDNode, dateCreated : System.DateTime, ?context : LDContext) = + lp.SetProperty(Dataset.dateCreated, dateCreated, ?context = context) + + static member tryGetDatePublishedAsDateTime(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.datePublished, ?context = context) with + | Some (:? System.DateTime as n) -> Some n + | _ -> None + + static member setDatePublishedAsDateTime(lp : LDNode, datePublished : System.DateTime, ?context : LDContext) = + lp.SetProperty(Dataset.datePublished, datePublished, ?context = context) + + static member tryGetSDDatePublishedAsDateTime(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.sdDatePublished, ?context = context) with + | Some (:? System.DateTime as n) -> Some n + | _ -> None + + static member setSDDatePublishedAsDateTime(lp : LDNode, sdDatePublished : System.DateTime, ?context : LDContext) = + lp.SetProperty(Dataset.sdDatePublished, sdDatePublished, ?context = context) + + static member tryGetLicenseAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.license, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + //static member tryGetLicenseAsCreativeWork(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + // match lp.TryGetPropertyAsSingleNode(Dataset.license, ?graph = graph, ?context = context) with + // | Some n when CreativeWork.validate(n, ?context = context) -> Some n + // | _ -> None + + static member setLicenseAsString(lp : LDNode, license : string, ?context : LDContext) = + lp.SetProperty(Dataset.license, license, ?context = context) + + static member setLicenseAsCreativeWork(lp : LDNode, license : obj, ?context : LDContext) = + lp.SetProperty(Dataset.license, license, ?context = context) + + static member tryGetDateModifiedAsDateTime(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.dateModified, ?context = context) with + | Some (:? System.DateTime as n) -> Some n + | _ -> None + + static member setDateModifiedAsDateTime(lp : LDNode, dateModified : System.DateTime, ?context : LDContext) = + lp.SetProperty(Dataset.dateModified, dateModified, ?context = context) + + static member tryGetDescriptionAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.description, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getDescriptionAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.description, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"property `description` of object with @id `{lp.Id}` was not a string" + | _ -> failwith $"Could not access property `description` of object with @id `{lp.Id}`" + + static member setDescriptionAsString(lp : LDNode, description : string, ?context : LDContext) = + lp.SetProperty(Dataset.description, description, ?context = context) + + static member getHasParts(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(Dataset.hasPart, ?graph = graph, ?context = context) + + static member getHasPartsAsDataset(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Dataset.validate(ldObject, ?context = context) + lp.GetPropertyNodes(Dataset.hasPart, filter = filter, ?graph = graph, ?context = context) + + static member getHasPartsAsFile(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = File.validate(ldObject, ?context = context) + lp.GetPropertyNodes(Dataset.hasPart, filter = filter, ?graph = graph, ?context = context) + + static member setHasParts(lp : LDNode, hasParts : ResizeArray, ?context : LDContext) = + lp.SetProperty(Dataset.hasPart, hasParts, ?context = context) + + static member tryGetHeadlineAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.headline, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member tryGetNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"property `name` of object with @id `{lp.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{lp.Id}`" + + static member setNameAsString(lp : LDNode, name : string, ?context : LDContext) = + lp.SetProperty(Dataset.name, name, ?context = context) + + static member getCitations(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = ScholarlyArticle.validate(ldObject, ?context = context) + lp.GetPropertyNodes(Dataset.citation, filter = filter, ?graph = graph, ?context = context) + + static member setCitations(lp : LDNode, citations : ResizeArray, ?context : LDContext) = + lp.SetProperty(Dataset.citation, citations, ?context = context) + + static member getComments(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Comment.validate(ldObject, ?context = context) + lp.GetPropertyNodes(Dataset.comment, filter = filter, ?graph = graph, ?context = context) + + static member setComments(lp : LDNode, comments : ResizeArray, ?context : LDContext) = + lp.SetProperty(Dataset.comment, comments, ?context = context) + + //static member getMentions(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + // let filter ldObject context = DefinedTermSet.validate(ldObject, ?context = context) + // lp.GetPropertyNodes(Dataset.mentions, filter = filter, ?graph = graph, ?context = context) + + //static member setMentions(lp : LDNode, mentions : ResizeArray, ?context : LDContext) = + // lp.SetProperty(Dataset.mentions, mentions, ?context = context) + + static member tryGetUrlAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.url, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getUrlAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.url, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"property `url` of object with @id `{lp.Id}` was not a string" + | _ -> failwith $"Could not access property `url` of object with @id `{lp.Id}`" + + static member setUrlAsString(lp : LDNode, url : string, ?context : LDContext) = + lp.SetProperty(Dataset.url, url, ?context = context) + + static member getAbouts(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(Dataset.about, ?graph = graph, ?context = context) + + static member getAboutsAsLabProcess(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = LabProcess.validate(ldObject, ?context = context) + lp.GetPropertyNodes(Dataset.about, filter = filter, ?graph = graph, ?context = context) + + static member setAbouts(lp : LDNode, abouts : ResizeArray, ?context : LDContext) = + lp.SetProperty(Dataset.about, abouts, ?context = context) + + static member tryGetMeasurementMethodAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.measurementMethod, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member tryGetMeasurementMethodAsDefinedTerm(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + match lp.TryGetPropertyAsSingleNode(Dataset.measurementMethod, ?graph = graph, ?context = context) with + | Some n when DefinedTerm.validate(n, ?context = context) -> Some n + | _ -> None + + static member setMeasurementMethodAsString(lp : LDNode, measurementMethod : string, ?context : LDContext) = + lp.SetProperty(Dataset.measurementMethod, measurementMethod, ?context = context) + + static member setMeasurementMethodAsDefinedTerm(lp : LDNode, measurementMethod : LDNode, ?context : LDContext) = + lp.SetProperty(Dataset.measurementMethod, measurementMethod, ?context = context) + + static member tryGetMeasurementTechniqueAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.measurementTechnique, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member tryGetMeasurementTechniqueAsDefinedTerm(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + match lp.TryGetPropertyAsSingleNode(Dataset.measurementTechnique, ?graph = graph, ?context = context) with + | Some n when DefinedTerm.validate(n, ?context = context) -> Some n + | _ -> None + + + static member setMeasurementTechniqueAsString(lp : LDNode, measurementTechnique : string, ?context : LDContext) = + lp.SetProperty(Dataset.measurementTechnique, measurementTechnique, ?context = context) + + static member setMeasurementTechniqueAsDefinedTerm(lp : LDNode, measurementTechnique : LDNode, ?context : LDContext) = + lp.SetProperty(Dataset.measurementTechnique, measurementTechnique, ?context = context) + + static member tryGetVariableMeasuredAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(Dataset.variableMeasured, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member tryGetVariableMeasuredAsPropertyValue(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + match lp.TryGetPropertyAsSingleNode(Dataset.variableMeasured, ?graph = graph, ?context = context) with + | Some n when PropertyValue.validate(n, ?context = context) -> Some n + | _ -> None + + static member setVariableMeasuredAsString(lp : LDNode, variableMeasured : string, ?context : LDContext) = + lp.SetProperty(Dataset.variableMeasured, variableMeasured, ?context = context) + + static member setVariableMeasuredAsPropertyValue(lp : LDNode, variableMeasured : LDNode, ?context : LDContext) = + lp.SetProperty(Dataset.variableMeasured, variableMeasured, ?context = context) + + static member genIDInvesigation() = + "./" + + static member genIDStudy(identifier : string) = + $"studies/{identifier}/" + + static member genIDAssay(identifier : string) = + $"assay/{identifier}/" + + static member validate(lp : LDNode, ?context : LDContext) = + lp.HasType(Dataset.schemaType, ?context = context) + + static member validateInvestigation(lp : LDNode, ?context : LDContext) = + Dataset.validate(lp, ?context = context) + && lp.AdditionalType.Contains("Investigation") + + static member validateStudy (lp : LDNode, ?context : LDContext) = + Dataset.validate(lp, ?context = context) + && lp.AdditionalType.Contains("Study") + + static member validateAssay (lp : LDNode, ?context : LDContext) = + Dataset.validate(lp, ?context = context) + && lp.AdditionalType.Contains("Assay") + + static member create(id : string, ?identier : string, ?creators : ResizeArray, ?dateCreated : System.DateTime, ?datePublished : System.DateTime, ?dateModified : System.DateTime, ?description : string, ?hasParts : ResizeArray, ?name : string, ?citations : ResizeArray, ?comments : ResizeArray, ?mentions : ResizeArray, ?url : string, ?abouts : ResizeArray, ?measurementMethod : LDNode, ?measurementTechnique : LDNode, ?variableMeasured : LDNode, ?context : LDContext) = + let s = LDNode(id, ResizeArray [Dataset.schemaType], ?context = context) + s.SetOptionalProperty(Dataset.identifier, identier, ?context = context) + s.SetOptionalProperty(Dataset.creator, creators, ?context = context) + s.SetOptionalProperty(Dataset.dateCreated, dateCreated, ?context = context) + s.SetOptionalProperty(Dataset.datePublished, datePublished, ?context = context) + s.SetOptionalProperty(Dataset.dateModified, dateModified, ?context = context) + s.SetOptionalProperty(Dataset.description, description, ?context = context) + s.SetOptionalProperty(Dataset.hasPart, hasParts, ?context = context) + s.SetOptionalProperty(Dataset.name, name, ?context = context) + s.SetOptionalProperty(Dataset.citation, citations, ?context = context) + s.SetOptionalProperty(Dataset.comment, comments, ?context = context) + s.SetOptionalProperty(Dataset.mentions, mentions, ?context = context) + s.SetOptionalProperty(Dataset.url, url, ?context = context) + s.SetOptionalProperty(Dataset.about, abouts, ?context = context) + s.SetOptionalProperty(Dataset.measurementMethod, measurementMethod, ?context = context) + s.SetOptionalProperty(Dataset.measurementTechnique, measurementTechnique, ?context = context) + s.SetOptionalProperty(Dataset.variableMeasured, variableMeasured, ?context = context) + s + + static member createInvestigation(identifier : string, name : string, ?id : string, ?creators : ResizeArray, ?dateCreated : System.DateTime, ?datePublished : System.DateTime, ?dateModified : System.DateTime, ?description : string, ?hasParts : ResizeArray, ?citations : ResizeArray, ?comments : ResizeArray, ?mentions : ResizeArray, ?url : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Dataset.genIDInvesigation() + let s = Dataset.create(id, identier = identifier, ?creators = creators, ?dateCreated = dateCreated, ?datePublished = datePublished, ?dateModified = dateModified, ?description = description, ?hasParts = hasParts, name = name, ?citations = citations, ?comments = comments, ?mentions = mentions, ?url = url, ?context = context) + s.AdditionalType <- ResizeArray ["Investigation"] + s + + static member createStudy(identifier : string, ?id : string, ?creators : ResizeArray, ?dateCreated : System.DateTime, ?datePublished : System.DateTime, ?dateModified : System.DateTime, ?description : string, ?hasParts : ResizeArray, ?name : string, ?citations : ResizeArray, ?comments : ResizeArray, ?url : string, ?abouts : ResizeArray, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Dataset.genIDStudy(identifier) + let s = Dataset.create(id, identier = identifier, ?creators = creators, ?dateCreated = dateCreated, ?datePublished = datePublished, ?dateModified = dateModified, ?description = description, ?hasParts = hasParts, ?name = name, ?citations = citations, ?comments = comments, ?url = url, ?abouts = abouts, ?context = context) + s.AdditionalType <- ResizeArray ["Study"] + s + + static member createAssay(identifier : string, ?id : string, ?description : string, ?creators : ResizeArray, ?hasParts : ResizeArray, ?measurementMethod : LDNode, ?measurementTechnique : LDNode, ?variableMeasured : LDNode, ?abouts : ResizeArray, ?comments : ResizeArray, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Dataset.genIDAssay(identifier) + let s = Dataset.create(id, identier = identifier, ?description = description, ?creators = creators, ?hasParts = hasParts, ?measurementMethod = measurementMethod, ?measurementTechnique = measurementTechnique, ?variableMeasured = variableMeasured, ?abouts = abouts, ?comments = comments, ?context = context) + s.AdditionalType <- ResizeArray ["Assay"] + s diff --git a/src/ROCrate/Generic/DefinedTerm.fs b/src/ROCrate/Generic/DefinedTerm.fs new file mode 100644 index 00000000..7071e124 --- /dev/null +++ b/src/ROCrate/Generic/DefinedTerm.fs @@ -0,0 +1,62 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +/// +[] +type DefinedTerm = + + static member schemaType = "http://schema.org/DefinedTerm" + + static member termCode = "http://schema.org/termCode" + + static member name = "http://schema.org/name" + + static member tryGetTermCodeAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(DefinedTerm.termCode, ?context = context) with + | Some (:? string as tc) -> Some tc + | _ -> None + + static member getTermCodeAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(DefinedTerm.termCode, ?context = context) with + | Some (:? string as tc) -> tc + | Some _ -> failwith $"Property of `termCode` of object with @id `{dt.Id}` was not a string" + | _ -> failwith $"Could not access property `termCode` of object with @id `{dt.Id}`" + + static member setTermCodeAsString(dt : LDNode, termCode : string, ?context : LDContext) = + dt.SetProperty(DefinedTerm.termCode, termCode, ?context = context) + + static member tryGetNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(DefinedTerm.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(DefinedTerm.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `name` of object with @id `{dt.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{dt.Id}`" + + static member setNameAsString(dt : LDNode, name : string, ?context : LDContext) = + dt.SetProperty(DefinedTerm.name, name, ?context = context) + + static member genID(name : string, ?termCode : string) = + match termCode with + | Some tc -> $"{tc}" + | None -> $"#OA_{name}" |> Helper.ID.clean + + + static member validate(dt : LDNode, ?context : LDContext) = + dt.HasType(DefinedTerm.schemaType, ?context = context) + && dt.HasProperty(DefinedTerm.name, ?context = context) + + static member create(name : string, ?id : string, ?termCode : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> DefinedTerm.genID(name, ?termCode = termCode) + let dt = LDNode(id, ResizeArray [DefinedTerm.schemaType], ?context = context) + dt.SetProperty(DefinedTerm.name, name, ?context = context) + dt.SetOptionalProperty(DefinedTerm.termCode, termCode, ?context = context) + dt \ No newline at end of file diff --git a/src/ROCrate/Generic/File.fs b/src/ROCrate/Generic/File.fs new file mode 100644 index 00000000..6b5ec7d8 --- /dev/null +++ b/src/ROCrate/Generic/File.fs @@ -0,0 +1,123 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +/// +[] +type File = + + static member schemaType = "http://schema.org/MediaObject" + + static member name = "http://schema.org/name" + + static member comment = "http://schema.org/comment" + + static member disambiguatingDescription = "http://schema.org/disambiguatingDescription" + + static member usageInfo = "http://schema.org/usageInfo" + + static member encodingFormat = "http://schema.org/encodingFormat" + + static member tryGetNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(File.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(File.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `name` of object with @id `{dt.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{dt.Id}`" + + static member setNameAsString(dt : LDNode, name : string, ?context : LDContext) = + dt.SetProperty(File.name, name, ?context = context) + + static member getComments(dt : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Comment.validate(ldObject, ?context = context) + dt.GetPropertyNodes(File.comment, filter = filter, ?graph = graph, ?context = context) + + static member setComments(dt : LDNode, comment : ResizeArray, ?context : LDContext) = + dt.SetProperty(File.comment, comment, ?context = context) + + static member tryGetDisambiguatingDescriptionAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(File.disambiguatingDescription, ?context = context) with + | Some (:? string as dd) -> Some dd + | _ -> None + + static member setDisambiguatingDescriptionAsString(dt : LDNode, disambiguatingDescription : string, ?context : LDContext) = + dt.SetProperty(File.disambiguatingDescription, disambiguatingDescription, ?context = context) + + static member tryGetEncodingFormatAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(File.encodingFormat, ?context = context) with + | Some (:? string as ef) -> Some ef + | _ -> None + + static member setEncodingFormatAsString(dt : LDNode, encodingFormat : string, ?context : LDContext) = + dt.SetProperty(File.encodingFormat, encodingFormat, ?context = context) + + static member tryGetUsageInfoAsString(dt : LDNode, ?context : LDContext) = + match dt.TryGetPropertyAsSingleton(File.usageInfo, ?context = context) with + | Some (:? string as ui) -> Some ui + | _ -> None + + static member setUsageInfoAsString(dt : LDNode, usageInfo : string, ?context : LDContext) = + dt.SetProperty(File.usageInfo, usageInfo, ?context = context) + + static member genId(name : string) = + $"{name}" + + static member validate(dt : LDNode, ?context : LDContext) = + dt.HasType(File.schemaType, ?context = context) + && dt.HasProperty(File.name, ?context = context) + + static member create(name : string, ?id : string, ?comments : ResizeArray, ?disambiguatingDescription : string, ?encodingFormat : string, ?usageInfo : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> File.genId(name) + let dt = LDNode(id, ResizeArray [File.schemaType], ?context = context) + dt.SetProperty(File.name, name, ?context = context) + dt.SetOptionalProperty(File.comment, comments, ?context = context) + dt.SetOptionalProperty(File.disambiguatingDescription, disambiguatingDescription, ?context = context) + dt.SetOptionalProperty(File.encodingFormat, encodingFormat, ?context = context) + dt.SetOptionalProperty(File.usageInfo, usageInfo, ?context = context) + dt + + //static member tryGetTermCodeAsString(dt : LDNode, ?context : LDContext) = + // match dt.TryGetProperty(DefinedTerm.termCode, ?context = context) with + // | Some (:? string as tc) -> Some tc + // | _ -> None + + //static member getTermCodeAsString(dt : LDNode, ?context : LDContext) = + // match dt.TryGetProperty(DefinedTerm.termCode, ?context = context) with + // | Some (:? string as tc) -> tc + // | Some _ -> failwith $"Property of `termCode` of object with @id `{dt.Id}` was not a string" + // | _ -> failwith $"Could not access property `termCode` of object with @id `{dt.Id}`" + + //static member setTermCodeAsString(dt : LDNode, termCode : string, ?context : LDContext) = + // dt.SetProperty(DefinedTerm.termCode, termCode, ?context = context) + + //static member tryGetNameAsString(dt : LDNode, ?context : LDContext) = + // match dt.TryGetProperty(DefinedTerm.name, ?context = context) with + // | Some (:? string as n) -> Some n + // | _ -> None + + //static member getNameAsString(dt : LDNode, ?context : LDContext) = + // match dt.TryGetProperty(DefinedTerm.name, ?context = context) with + // | Some (:? string as n) -> n + // | Some _ -> failwith $"Property of `name` of object with @id `{dt.Id}` was not a string" + // | _ -> failwith $"Could not access property `name` of object with @id `{dt.Id}`" + + //static member setNameAsString(dt : LDNode, name : string, ?context : LDContext) = + // dt.SetProperty(DefinedTerm.name, name, ?context = context) + + //static member validate(dt : LDNode, ?context : LDContext) = + // dt.HasType(DefinedTerm.schemaType, ?context = context) + // && dt.HasProperty(DefinedTerm.name, ?context = context) + + //static member create(id : string, name : string, ?termCode : string, ?context : LDContext) = + // let dt = LDNode(id, ResizeArray [DefinedTerm.schemaType], ?context = context) + // dt.SetProperty(DefinedTerm.name, name, ?context = context) + // dt.SetOptionalProperty(DefinedTerm.termCode, termCode, ?context = context) + // dt \ No newline at end of file diff --git a/src/ROCrate/Generic/LabProcess.fs b/src/ROCrate/Generic/LabProcess.fs new file mode 100644 index 00000000..1c0e5662 --- /dev/null +++ b/src/ROCrate/Generic/LabProcess.fs @@ -0,0 +1,151 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate +open ARCtrl.Helper + +[] +type LabProcess = + + static member schemaType = "https://bioschemas.org/LabProcess" + + static member name = "http://schema.org/name" + + static member agent = "http://schema.org/agent" + + static member object_ = "http://schema.org/object" + + static member result = "http://schema.org/result" + + static member executesLabProtocol = "https://bioschemas.org/executesLabProtocol" + + static member parameterValue = "https://bioschemas.org/parameterValue" + + static member endTime = "http://schema.org/endTime" + + static member disambiguatingDescription = "http://schema.org/disambiguatingDescription" + + static member tryGetNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProcess.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProcess.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"property `name` of object with @id `{lp.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{lp.Id}`" + + static member setNameAsString(lp : LDNode, name : string, ?context : LDContext) = + lp.SetProperty(LabProcess.name, name, ?context = context) + + static member tryGetAgent(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Person.validate(ldObject, ?context = context) + match lp.TryGetPropertyAsSingleNode(LabProcess.agent, ?graph = graph, ?context = context) with + | Some a when filter a context -> Some a + | _ -> None + + static member getAgent(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Person.validate(ldObject, ?context = context) + match lp.TryGetPropertyAsSingleNode(LabProcess.agent, ?graph = graph, ?context = context) with + | Some a when filter a context -> a + | Some _ -> failwith $"Property of `agent` of object with @id `{lp.Id}` was not a valid Person" + | _ -> failwith $"Could not access property `agent` of object with @id `{lp.Id}`" + + static member setAgent(lp : LDNode, agent : LDNode, ?context : LDContext) = + lp.SetProperty(LabProcess.agent, agent, ?context = context) + + static member getObjects(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(LabProcess.object_, ?graph = graph, ?context = context) + + static member getObjectsAsSample(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Sample.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProcess.object_, filter = filter, ?graph = graph, ?context = context) + + static member getObjectsAsData(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = File.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProcess.object_, filter = filter, ?graph = graph, ?context = context) + + static member setObjects(lp : LDNode, objects : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProcess.object_, objects, ?context = context) + + static member getResults(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(LabProcess.result, ?graph = graph, ?context = context) + + static member getResultsAsSample(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Sample.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProcess.result, filter = filter, ?graph = graph, ?context = context) + + static member getResultsAsData(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = File.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProcess.result, filter = filter, ?graph = graph, ?context = context) + + static member setResults(lp : LDNode, results : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProcess.result, results, ?context = context) + + static member tryGetExecutesLabProtocol(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = LabProtocol.validate(ldObject, ?context = context) + match lp.TryGetPropertyAsSingleNode(LabProcess.executesLabProtocol, ?graph = graph, ?context = context) with + | Some l when filter l context -> Some l + | _ -> None + + static member setExecutesLabProtocol(lp : LDNode, executesLabProtocol : LDNode, ?context : LDContext) = + lp.SetProperty(LabProcess.executesLabProtocol, executesLabProtocol, ?context = context) + + static member getParameterValues(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = PropertyValue.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProcess.parameterValue, filter = filter, ?graph = graph, ?context = context) + + static member setParameterValues(lp : LDNode, parameterValues : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProcess.parameterValue, parameterValues, ?context = context) + + static member tryGetEndTime(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProcess.endTime, ?context = context) with + | Some (:? System.DateTime as et) -> Some et + | _ -> None + + static member setEndTime(lp : LDNode, endTime : System.DateTime, ?context : LDContext) = + lp.SetProperty(LabProcess.endTime, endTime, ?context = context) + + + static member getDisambiguatingDescriptionsAsString(lp : LDNode, ?context : LDContext) = + let filter = fun (o : obj) context -> o :? string + lp.GetPropertyValues(LabProcess.disambiguatingDescription, filter = filter, ?context = context) + |> ResizeArray.map (fun (o : obj) -> o :?> string) + + static member setDisambiguatingDescriptionsAsString(lp : LDNode, disambiguatingDescriptions : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProcess.disambiguatingDescription, disambiguatingDescriptions, ?context = context) + + static member validate(lp : LDNode, ?context : LDContext) = + lp.HasType(LabProcess.schemaType, ?context = context) + && lp.HasProperty(LabProcess.name, ?context = context) + //&& lp.HasProperty(LabProcess.agent, ?context = context) + //&& lp.HasProperty(LabProcess.object_, ?context = context) + //&& lp.HasProperty(LabProcess.result, ?context = context) + + static member genId(name, ?assayName, ?studyName) = + match assayName, studyName with + | Some assay, Some study -> $"#Process_{study}_{assay}_{name}" + | Some assay, None -> $"#Process_{assay}_{name}" + | None, Some study -> $"#Process_{study}_{name}" + | _ -> $"#Process_{name}" + |> Helper.ID.clean + + + static member create(name : string, ?objects : ResizeArray, ?results : ResizeArray, ?id : string, ?agent : LDNode, ?executesLabProtocol : LDNode, ?parameterValues : ResizeArray, ?endTime : System.DateTime, ?disambiguatingDescriptions : ResizeArray, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> LabProcess.genId(name) + let objects = Option.defaultValue (ResizeArray []) objects + let results = Option.defaultValue (ResizeArray []) results + let lp = LDNode(id, ResizeArray [LabProcess.schemaType], ?context = context) + lp.SetProperty(LabProcess.name, name, ?context = context) + lp.SetOptionalProperty(LabProcess.agent, agent, ?context = context) // Optional? + lp.SetProperty(LabProcess.object_, objects, ?context = context) + lp.SetProperty(LabProcess.result, results, ?context = context) + lp.SetOptionalProperty(LabProcess.executesLabProtocol, executesLabProtocol, ?context = context) + lp.SetOptionalProperty(LabProcess.parameterValue, parameterValues, ?context = context) + lp.SetOptionalProperty(LabProcess.endTime, endTime, ?context = context) + lp.SetOptionalProperty(LabProcess.disambiguatingDescription, disambiguatingDescriptions, ?context = context) + lp \ No newline at end of file diff --git a/src/ROCrate/Generic/LabProtocol.fs b/src/ROCrate/Generic/LabProtocol.fs new file mode 100644 index 00000000..6a7a5576 --- /dev/null +++ b/src/ROCrate/Generic/LabProtocol.fs @@ -0,0 +1,145 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +[] +type LabProtocol = + + static member schemaType = "https://bioschemas.org/LabProtocol" + + static member description = "http://schema.org/description" + + static member intendedUse = "https://bioschemas.org/intendedUse" + + static member name = "http://schema.org/name" + + static member comment = "http://schema.org/comment" + + static member computationalTool = "https://bioschemas.org/computationalTool" + + static member labEquipment = "https://bioschemas.org/labEquipment" + + static member reagent = "https://bioschemas.org/reagent" + + static member url = "http://schema.org/url" + + static member version = "http://schema.org/version" + + + static member tryGetDescriptionAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.description, ?context = context) with + | Some (:? string as d) -> Some d + | _ -> None + + static member setDescriptionAsString(lp : LDNode, description : string, ?context : LDContext) = + lp.SetProperty(LabProtocol.description, description, ?context = context) + + static member tryGetIntendedUseAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.intendedUse, ?context = context) with + | Some (:? string as iu) -> Some iu + | _ -> None + + static member setIntendedUseAsString(lp : LDNode, intendedUse : string, ?context : LDContext) = + lp.SetProperty(LabProtocol.intendedUse, intendedUse, ?context = context) + + static member tryGetIntendedUseAsDefinedTerm(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = DefinedTerm.validate(ldObject, ?context = context) + match lp.TryGetPropertyAsSingleNode(LabProtocol.intendedUse, ?graph = graph, ?context = context) with + | Some iu when filter iu context -> Some iu + | _ -> None + + static member setIntendedUseAsDefinedTerm(lp : LDNode, intendedUse : LDNode, ?context : LDContext) = + lp.SetProperty(LabProtocol.intendedUse, intendedUse, ?context = context) + + static member tryGetNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.name, ?context = context) with + | Some (:? string as n) -> n + | _ -> failwith $"Could not access property `name` of object with @id `{lp.Id}`" + + static member setNameAsString(lp : LDNode, name : string, ?context : LDContext) = + lp.SetProperty(LabProtocol.name, name, ?context = context) + + static member getComments(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Comment.validate(ldObject, ?context = context) + lp.GetPropertyNodes(LabProtocol.comment, filter = filter, ?graph = graph, ?context = context) + + static member setComments(lp : LDNode, comments : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProtocol.comment, comments, ?context = context) + + static member getComputationalTools(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(LabProtocol.computationalTool, ?graph = graph, ?context = context) + + static member setComputationalTools(lp : LDNode, computationalTools : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProtocol.computationalTool, computationalTools, ?context = context) + + static member getLabEquipments(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(LabProtocol.labEquipment, ?graph = graph, ?context = context) + + static member setLabEquipments(lp : LDNode, labEquipments : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProtocol.labEquipment, labEquipments, ?context = context) + + static member getReagents(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + lp.GetPropertyNodes(LabProtocol.reagent, ?graph = graph, ?context = context) + + static member setReagents(lp : LDNode, reagents : ResizeArray, ?context : LDContext) = + lp.SetProperty(LabProtocol.reagent, reagents, ?context = context) + + static member getComponents(lp : LDNode, ?graph : LDGraph, ?context : LDContext) = + LabProtocol.getLabEquipments(lp, ?graph = graph, ?context = context) + |> Seq.append (LabProtocol.getReagents(lp, ?graph = graph, ?context = context)) + |> Seq.append (LabProtocol.getComputationalTools(lp, ?graph = graph, ?context = context)) + |> ResizeArray + + static member tryGetUrl(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.url, ?context = context) with + | Some (:? string as u) -> Some u + | _ -> None + + static member setUrl(lp : LDNode, url : string, ?context : LDContext) = + lp.SetProperty(LabProtocol.url, url, ?context = context) + + static member tryGetVersionAsString(lp : LDNode, ?context : LDContext) = + match lp.TryGetPropertyAsSingleton(LabProtocol.version, ?context = context) with + | Some (:? string as v) -> Some v + | _ -> None + + static member setVersionAsString(lp : LDNode, version : string, ?context : LDContext) = + lp.SetProperty(LabProtocol.version, version, ?context = context) + + static member validate(lp : LDNode, ?context : LDContext) = + lp.HasType(LabProtocol.schemaType, ?context = context) + //&& lp.HasProperty(LabProtocol.name, ?context = context) + + static member genId(?name : string, ?processName : string, ?assayName : string, ?studyName : string) = + [ + if name.IsSome then name.Value + if processName.IsSome then processName.Value + if assayName.IsSome then assayName.Value + if studyName.IsSome then studyName.Value + ] + |> fun vals -> + if vals.IsEmpty then [ARCtrl.Helper.Identifier.createMissingIdentifier()] + else vals + |> List.append ["#Protocol"] + |> String.concat "_" + |> Helper.ID.clean + + static member create(id : string, ?name : string, ?description : string, ?intendedUse : LDNode, ?comments : ResizeArray, ?computationalTools : ResizeArray, ?labEquipments : ResizeArray, ?reagents : ResizeArray, ?url : string, ?version : string, ?context : LDContext) = + let lp = LDNode(id, ResizeArray [LabProtocol.schemaType], ?context = context) + lp.SetOptionalProperty(LabProtocol.name, name, ?context = context) + lp.SetOptionalProperty(LabProtocol.description, description, ?context = context) + lp.SetOptionalProperty(LabProtocol.intendedUse, intendedUse, ?context = context) + lp.SetOptionalProperty(LabProtocol.comment, comments, ?context = context) + lp.SetOptionalProperty(LabProtocol.computationalTool, computationalTools, ?context = context) + lp.SetOptionalProperty(LabProtocol.labEquipment, labEquipments, ?context = context) + lp.SetOptionalProperty(LabProtocol.reagent, reagents, ?context = context) + lp.SetOptionalProperty(LabProtocol.url, url, ?context = context) + lp.SetOptionalProperty(LabProtocol.version, version, ?context = context) + lp \ No newline at end of file diff --git a/src/ROCrate/Generic/Organization.fs b/src/ROCrate/Generic/Organization.fs new file mode 100644 index 00000000..6ef0113d --- /dev/null +++ b/src/ROCrate/Generic/Organization.fs @@ -0,0 +1,42 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate +/// +[] +type Organization = + + static member schemaType = "http://schema.org/Organization" + + static member name = "http://schema.org/name" + + static member tryGetNameAsString(o : LDNode, ?context : LDContext) = + match o.TryGetPropertyAsSingleton(Organization.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(o : LDNode, ?context : LDContext) = + match o.TryGetPropertyAsSingleton(Organization.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `name` of object with @id `{o.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{o.Id}`" + + static member setNameAsString(o : LDNode, n : string, ?context : LDContext) = + o.SetProperty(Organization.name, n, ?context = context) + + static member genID(name : string) = + $"#Organization_{name}" + |> Helper.ID.clean + + static member validate(o : LDNode, ?context : LDContext) = + o.HasType(Organization.schemaType, ?context = context) + && o.HasProperty(Organization.name, ?context = context) + + static member create(name : string, ?id : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Organization.genID name + let o = LDNode(id, ResizeArray [Organization.schemaType], ?context = context) + o.SetProperty(Organization.name, name, ?context = context) + o \ No newline at end of file diff --git a/src/ROCrate/Generic/Person.fs b/src/ROCrate/Generic/Person.fs new file mode 100644 index 00000000..9c69d19b --- /dev/null +++ b/src/ROCrate/Generic/Person.fs @@ -0,0 +1,168 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate +open ARCtrl.Helper + +[] +type Person = + + static member schemaType = "http://schema.org/Person" + static member givenName = "http://schema.org/givenName" + static member affiliation = "http://schema.org/affiliation" + static member email = "http://schema.org/email" + static member familyName = "http://schema.org/familyName" + static member identifier = "http://schema.org/identifier" + static member jobTitle = "http://schema.org/jobTitle" + static member additionalName = "http://schema.org/additionalName" + static member address = "http://schema.org/address" + static member disambiguatingDescription = "http://schema.org/disambiguatingDescription" + static member faxNumber = "http://schema.org/faxNumber" + static member telephone = "http://schema.org/telephone" + + static member tryGetGivenNameAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.givenName, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getGivenNameAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.givenName, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `givenName` of object with @id `{p.Id}` was not a string" + | _ -> failwith $"Could not access property `givenName` of object with @id `{p.Id}`" + + static member setGivenNameAsString(p : LDNode, n : string, ?context : LDContext) = + p.SetProperty(Person.givenName, n, ?context = context) + + static member tryGetAffiliation(p : LDNode, ?graph :LDGraph, ?context : LDContext) = + match p.TryGetPropertyAsSingleNode(Person.affiliation, ?graph = graph, ?context = context) with + | Some n when Organization.validate n -> Some n + | _ -> None + + static member setAffiliation(p : LDNode, a : LDNode, ?context : LDContext) = + p.SetProperty(Person.affiliation, a, ?context = context) + + static member tryGetEmailAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.email, ?context = context) with + | Some (:? string as e) -> Some e + | _ -> None + + static member setEmailAsString(p : LDNode, e : string, ?context : LDContext) = + p.SetProperty(Person.email, e, ?context = context) + + static member tryGetFamilyNameAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.familyName, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getFamilyNameAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.familyName, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `familyName` of object with @id `{p.Id}` was not a string" + | _ -> failwith $"Could not access property `familyName` of object with @id `{p.Id}`" + + static member setFamilyNameAsString(p : LDNode, n : string, ?context : LDContext) = + p.SetProperty(Person.familyName, n, ?context = context) + + static member tryGetIdentifier(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.identifier, ?context = context) with + | Some (:? LDNode as i) -> Some i + | _ -> None + + static member setIdentifier(p : LDNode, i : LDNode, ?context : LDContext) = + p.SetProperty(Person.identifier, i, ?context = context) + + static member getJobTitlesAsDefinedTerm(p : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = DefinedTerm.validate(ldObject, ?context = context) + p.GetPropertyNodes(Person.jobTitle, filter = filter, ?graph = graph, ?context = context) + + + static member setJobTitleAsDefinedTerm(p : LDNode, j : ResizeArray, ?context : LDContext) = + p.SetProperty(Person.jobTitle, j, ?context = context) + + static member tryGetAdditionalNameAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.additionalName, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member setAdditionalNameAsString(p : LDNode, n : string, ?context : LDContext) = + p.SetProperty(Person.additionalName, n, ?context = context) + + static member tryGetAddress(p : LDNode, ?graph : LDGraph, ?context : LDContext) : obj option = + match p.TryGetPropertyAsSingleton(Person.address, ?context = context) with + | Some (:? LDRef as r) when graph.IsSome -> graph.Value.TryGetNode(r.Id) |> Option.map box + | Some (:? LDNode as a) -> Some a + | Some (:? string as s) -> Some s + | _ -> None + + static member tryGetAddressAsPostalAddress(p : LDNode, ?graph : LDGraph, ?context : LDContext) = + match p.TryGetPropertyAsSingleNode(Person.address, ?graph = graph, ?context = context) with + | Some n when PostalAddress.validate n -> Some n + | _ -> None + + static member tryGetAddressAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.address, ?context = context) with + | Some (:? string as a) -> Some a + | _ -> None + + static member setAddressAsPostalAddress(p : LDNode, a : LDNode, ?context : LDContext) = + p.SetProperty(Person.address, a, ?context = context) + + static member setAddressAsString(p : LDNode, a : string, ?context : LDContext) = + p.SetProperty(Person.address, a, ?context = context) + + static member getDisambiguatingDescriptionsAsString(p : LDNode, ?context : LDContext) = + let filter (value : obj) context = value :? string + p.GetPropertyValues(Person.disambiguatingDescription, filter = filter, ?context = context) + |> ResizeArray.map (fun v -> v :?> string) + + static member setDisambiguatingDescriptionsAsString(p : LDNode, d : ResizeArray, ?context : LDContext) = + p.SetProperty(Person.disambiguatingDescription, d, ?context = context) + + static member tryGetFaxNumberAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.faxNumber, ?context = context) with + | Some (:? string as f) -> Some f + | _ -> None + + static member setFaxNumberAsString(p : LDNode, f : string, ?context : LDContext) = + p.SetProperty(Person.faxNumber, f, ?context = context) + + static member tryGetTelephoneAsString(p : LDNode, ?context : LDContext) = + match p.TryGetPropertyAsSingleton(Person.telephone, ?context = context) with + | Some (:? string as t) -> Some t + | _ -> None + + static member setTelephoneAsString(p : LDNode, t : string, ?context : LDContext) = + p.SetProperty(Person.telephone, t, ?context = context) + + static member genId(givenName, ?orcid, ?familyName) = + match orcid |> Option.bind ORCID.tryGetOrcidURL with + | Some orcid -> orcid + | None -> + match familyName with + | Some familyName -> $"#Person_{givenName}_{familyName}" + | None -> $"#Person_{givenName}" + |> Helper.ID.clean + + static member validate(p : LDNode, ?context : LDContext) = + p.HasType(Person.schemaType, ?context = context) + && p.HasProperty(Person.givenName, ?context = context) + + static member create(givenName : string, ?orcid : string, ?id : string, ?affiliation : #obj, ?email : string, ?familyName : string, ?identifier, ?jobTitles : ResizeArray, ?additionalName : string, ?address : #obj, ?disambiguatingDescriptions : ResizeArray, ?faxNumber : string, ?telephone : string, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> Person.genId(givenName, ?orcid = orcid, ?familyName = familyName) + let person = LDNode(id, ResizeArray [Person.schemaType], ?context = context) + person.SetProperty(Person.givenName, givenName, ?context = context) + person.SetOptionalProperty(Person.affiliation, affiliation, ?context = context) + person.SetOptionalProperty(Person.email, email, ?context = context) + person.SetOptionalProperty(Person.familyName, familyName, ?context = context) + person.SetOptionalProperty(Person.identifier, identifier, ?context = context) + person.SetOptionalProperty(Person.jobTitle, jobTitles, ?context = context) + person.SetOptionalProperty(Person.additionalName, additionalName, ?context = context) + person.SetOptionalProperty(Person.address, address, ?context = context) + person.SetOptionalProperty(Person.disambiguatingDescription, disambiguatingDescriptions, ?context = context) + person.SetOptionalProperty(Person.faxNumber, faxNumber, ?context = context) + person.SetOptionalProperty(Person.telephone, telephone, ?context = context) + person \ No newline at end of file diff --git a/src/ROCrate/Generic/PostalAddress.fs b/src/ROCrate/Generic/PostalAddress.fs new file mode 100644 index 00000000..2a5833b2 --- /dev/null +++ b/src/ROCrate/Generic/PostalAddress.fs @@ -0,0 +1,87 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.Helper + +/// +[] +type PostalAddress = + + static member schemaType = "http://schema.org/PostalAddress" + + static member addressCountry = "http://schema.org/addressCountry" + + static member postalCode = "http://schema.org/postalCode" + + static member streetAddress = "http://schema.org/streetAddress" + + static member tryGetAddressCountryAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.addressCountry, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getAddressCountryAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.addressCountry, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Value of property `addressCountry` of object with @id `{s.Id}` should have been a string" + | None -> failwith $"Could not access property `addressCountry` of object with @id `{s.Id}`" + + static member setAddressCountryAsString(s : LDNode, n : string) = + s.SetProperty(PostalAddress.addressCountry, n) + + static member tryGetPostalCodeAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.postalCode, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getPostalCodeAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.postalCode, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Value of property `postalCode` of object with @id `{s.Id}` should have been a string" + | None -> failwith $"Could not access property `postalCode` of object with @id `{s.Id}`" + + static member setPostalCodeAsString(s : LDNode, n : string) = + s.SetProperty(PostalAddress.postalCode, n) + + static member tryGetStreetAddressAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.streetAddress, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getStreetAddressAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(PostalAddress.streetAddress, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Value of property `streetAddress` of object with @id `{s.Id}` should have been a string" + | None -> failwith $"Could not access property `streetAddress` of object with @id `{s.Id}`" + + static member setStreetAddressAsString(s : LDNode, n : string) = + s.SetProperty(PostalAddress.streetAddress, n) + + static member genID(?addressCountry : string, ?postalCode : string, ?streetAddress : string) = + let items = + [ + if addressCountry.IsSome then yield "addressCountry" + if postalCode.IsSome then yield "postalCode" + if streetAddress.IsSome then yield "streetAddress" + ] + if items.IsEmpty then Identifier.createMissingIdentifier() + else + items + |> List.reduce (fun acc x -> $"{acc}_{x}") + |> sprintf "#%s" + |> Helper.ID.clean + + static member validate(o : LDNode, ?context : LDContext) = + o.HasType(PostalAddress.schemaType, ?context = context) + + static member create(?id : string, ?addressCountry : string, ?postalCode : string, ?streetAddress : string, ?context : LDContext) = + let id = + match id with + | Some x -> x + | None -> PostalAddress.genID(?addressCountry = addressCountry, ?postalCode = postalCode, ?streetAddress = streetAddress) + let s = LDNode(id, ResizeArray [PostalAddress.schemaType], ?context = context) + s.SetOptionalProperty(PostalAddress.addressCountry, addressCountry) + s.SetOptionalProperty(PostalAddress.postalCode, postalCode) + s.SetOptionalProperty(PostalAddress.streetAddress, streetAddress) + s \ No newline at end of file diff --git a/src/ROCrate/Generic/PropertyValue.fs b/src/ROCrate/Generic/PropertyValue.fs new file mode 100644 index 00000000..b54af2a8 --- /dev/null +++ b/src/ROCrate/Generic/PropertyValue.fs @@ -0,0 +1,171 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +/// +[] +type PropertyValue = + + static member schemaType = "http://schema.org/PropertyValue" + + static member name = "http://schema.org/name" + + static member value = "http://schema.org/value" + + static member propertyID = "http://schema.org/propertyID" + + static member unitCode = "http://schema.org/unitCode" + + static member unitText = "http://schema.org/unitText" + + static member valueReference = "http://schema.org/valueReference" + + static member tryGetNameAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.name, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Property of `name` of object with @id `{pv.Id}` was not a string" + | _ -> failwith $"Could not access property `name` of object with @id `{pv.Id}`" + + static member setNameAsString(pv : LDNode, name : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.name, name, ?context = context) + + static member tryGetValueAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.value, ?context = context) with + | Some (:? string as v) -> Some v + | _ -> None + + static member getValueAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.value, ?context = context) with + | Some (:? string as v) -> v + | Some _ -> failwith $"Property of `value` of object with @id `{pv.Id}` was not a string" + | _ -> failwith $"Could not access property `value` of object with @id `{pv.Id}`" + + static member setValueAsString(pv : LDNode, value : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.value, value, ?context = context) + + static member tryGetPropertyIDAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.propertyID, ?context = context) with + | Some (:? string as pid) -> Some pid + | _ -> None + + static member setPropertyIDAsString(pv : LDNode, propertyID : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.propertyID, propertyID, ?context = context) + + static member tryGetUnitCodeAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.unitCode, ?context = context) with + | Some (:? string as uc) -> Some uc + | _ -> None + + static member setUnitCodeAsString(pv : LDNode, unitCode : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.unitCode, unitCode, ?context = context) + + static member tryGetUnitTextAsString(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.unitText, ?context = context) with + | Some (:? string as ut) -> Some ut + | _ -> None + + static member setUnitTextAsString(pv : LDNode, unitText : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.unitText, unitText, ?context = context) + + static member tryGetValueReference(pv : LDNode, ?context : LDContext) = + match pv.TryGetPropertyAsSingleton(PropertyValue.valueReference, ?context = context) with + | Some (:? string as vr) -> Some vr + | _ -> None + + static member setValueReference(pv : LDNode, valueReference : string, ?context : LDContext) = + pv.SetProperty(PropertyValue.valueReference, valueReference, ?context = context) + + static member validate(pv : LDNode, ?context : LDContext) = + pv.HasType(PropertyValue.schemaType, ?context = context) + && pv.HasProperty(PropertyValue.name, ?context = context) + //&& pv.HasProperty(PropertyValue.value, ?context = context) + + static member validateComponent (pv : LDNode, ?context : LDContext) = + PropertyValue.validate(pv, ?context = context) + && pv.AdditionalType.Contains("Component") + + static member validateParameterValue (pv : LDNode, ?context : LDContext) = + PropertyValue.validate(pv, ?context = context) + && pv.AdditionalType.Contains("ParameterValue") + + static member validateCharacteristicValue (pv : LDNode, ?context : LDContext) = + PropertyValue.validate(pv, ?context = context) + && pv.AdditionalType.Contains("CharacteristicValue") + + static member validateFactorValue (pv : LDNode, ?context : LDContext) = + PropertyValue.validate(pv, ?context = context) + && pv.AdditionalType.Contains("FactorValue") + + static member genId(name : string, ?value : string, ?propertyID : string, ?prefix) = + let prefix = Option.defaultValue "PV" prefix + match value,propertyID with + | Some value, Some pid -> $"#{prefix}_{name}_{value}"(*_{pid}*) + | Some value, None -> $"#{prefix}_{name}_{value}" + | None, Some pid -> $"#{prefix}_{name}"(*_{pid}*) + | _ -> $"#{prefix}_{name}" + |> Helper.ID.clean + + static member genIdComponent(name : string, ?value : string, ?propertyID : string) = + PropertyValue.genId(name, ?value = value, ?propertyID = propertyID, prefix = "Component") + + static member genIdParameterValue(name : string, ?value : string, ?propertyID : string) = + PropertyValue.genId(name, ?value = value, ?propertyID = propertyID, prefix = "ParameterValue") + + static member genIdCharacteristicValue(name : string, ?value : string, ?propertyID : string) = + PropertyValue.genId(name, ?value = value, ?propertyID = propertyID, prefix = "CharacteristicValue") + + static member genIdFactorValue(name : string, ?value : string, ?propertyID : string) = + PropertyValue.genId(name, ?value = value, ?propertyID = propertyID, prefix = "FactorValue") + + static member create(name, ?value, ?id : string, ?propertyID, ?unitCode, ?unitText, ?valueReference, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> PropertyValue.genId(name, ?value = value, ?propertyID = propertyID) + let pv = LDNode(id, schemaType = ResizeArray [PropertyValue.schemaType], ?context = context) + PropertyValue.setNameAsString(pv, name, ?context = context) + //PropertyValue.setValueAsString(pv, value, ?context = context) + pv.SetOptionalProperty(PropertyValue.value, value, ?context = context) + propertyID |> Option.iter (fun pid -> PropertyValue.setPropertyIDAsString(pv, pid, ?context = context)) + unitCode |> Option.iter (fun uc -> PropertyValue.setUnitCodeAsString(pv, uc, ?context = context)) + unitText |> Option.iter (fun ut -> PropertyValue.setUnitTextAsString(pv, ut, ?context = context)) + valueReference |> Option.iter (fun vr -> PropertyValue.setValueReference(pv, vr, ?context = context)) + pv + + static member createComponent(name, ?value, ?id, ?propertyID, ?unitCode, ?unitText, ?valueReference, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> PropertyValue.genIdComponent(name, ?value = value, ?propertyID = propertyID) + let c = PropertyValue.create(name, id = id, ?value = value, ?propertyID = propertyID, ?unitCode = unitCode, ?unitText = unitText, ?valueReference = valueReference, ?context = context) + c.AdditionalType <- ResizeArray ["Component"] + c + + static member createParameterValue(name, ?value, ?id, ?propertyID, ?unitCode, ?unitText, ?valueReference, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> PropertyValue.genIdParameterValue(name, ?value = value, ?propertyID = propertyID) + let pv = PropertyValue.create(name, id = id, ?value = value, ?propertyID = propertyID, ?unitCode = unitCode, ?unitText = unitText, ?valueReference = valueReference, ?context = context) + pv.AdditionalType <- ResizeArray ["ParameterValue"] + pv + + static member createCharacteristicValue(name, ?value, ?id, ?propertyID, ?unitCode, ?unitText, ?valueReference, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> PropertyValue.genIdCharacteristicValue(name, ?value = value, ?propertyID = propertyID) + let cv = PropertyValue.create(name, id = id, ?value = value, ?propertyID = propertyID, ?unitCode = unitCode, ?unitText = unitText, ?valueReference = valueReference, ?context = context) + cv.AdditionalType <- ResizeArray ["CharacteristicValue"] + cv + + static member createFactorValue(name, ?value, ?id, ?propertyID, ?unitCode, ?unitText, ?valueReference, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> PropertyValue.genIdFactorValue(name, ?value = value, ?propertyID = propertyID) + let fv = PropertyValue.create(name, id = id, ?value = value, ?propertyID = propertyID, ?unitCode = unitCode, ?unitText = unitText, ?valueReference = valueReference, ?context = context) + fv.AdditionalType <- ResizeArray ["FactorValue"] + fv \ No newline at end of file diff --git a/src/ROCrate/Generic/Sample.fs b/src/ROCrate/Generic/Sample.fs new file mode 100644 index 00000000..53f748b2 --- /dev/null +++ b/src/ROCrate/Generic/Sample.fs @@ -0,0 +1,101 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate + +/// +[] +type Sample = + + static member schemaType = "https://bioschemas.org/Sample" + + static member name = "http://schema.org/name" + + static member additionalProperty = "http://schema.org/additionalProperty" + + static member tryGetNameAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(Sample.name, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getNameAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(Sample.name, ?context = context) with + | Some (:? string as n) -> n + | _ -> failwith $"Could not access property `name` of object with @id `{s.Id}`" + + static member setNameAsString(s : LDNode, n : string) = + s.SetProperty(Sample.name, n) + + static member getAdditionalProperties(s : LDNode, ?graph : LDGraph, ?context : LDContext) : ResizeArray = + let filter ldObject context = PropertyValue.validate(ldObject, ?context = context) + s.GetPropertyNodes(Sample.additionalProperty, filter = filter, ?graph = graph, ?context = context) + + static member setAdditionalProperties(s : LDNode, additionalProperties : ResizeArray, ?context : LDContext) = + s.SetProperty(Sample.additionalProperty, additionalProperties, ?context = context) + + static member getCharacteristics(s : LDNode, ?graph : LDGraph, ?context : LDContext) : ResizeArray = + let filter ldObject context = PropertyValue.validateCharacteristicValue(ldObject, ?context = context) + s.GetPropertyNodes(Sample.additionalProperty, filter = filter, ?graph = graph, ?context = context) + + static member getFactors(s : LDNode, ?graph : LDGraph, ?context : LDContext) : ResizeArray = + let filter ldObject context = PropertyValue.validateFactorValue(ldObject, ?context = context) + s.GetPropertyNodes(Sample.additionalProperty, filter = filter, ?graph = graph, ?context = context) + + static member validate(s : LDNode, ?context : LDContext) = + s.HasType(Sample.schemaType, ?context = context) + && s.HasProperty(Sample.name, ?context = context) + + static member genIDSample(name : string) = + $"#Sample_{name}" + |> Helper.ID.clean + + static member genIDSource(name : string) = + $"#Source_{name}" + |> Helper.ID.clean + + static member genIDMaterial(name : string) = + $"#Material_{name}" + |> Helper.ID.clean + + static member validateSample (s : LDNode, ?context : LDContext) = + Sample.validate(s, ?context = context) + && s.AdditionalType.Contains("Sample") + + static member validateSource (s : LDNode, ?context : LDContext) = + Sample.validate(s, ?context = context) + && s.AdditionalType.Contains("Source") + + static member validateMaterial (s : LDNode, ?context : LDContext) = + Sample.validate(s, ?context = context) + && s.AdditionalType.Contains("Material") + + static member create(id : string, name : string, ?additionalProperties : ResizeArray, ?context : LDContext) = + let s = LDNode(id, ResizeArray [Sample.schemaType], ?context = context) + s.SetProperty(Sample.name, name, ?context = context) + s.SetOptionalProperty(Sample.additionalProperty, additionalProperties, ?context = context) + s + + static member createSample (name : string, ?id : string, ?additionalProperties : ResizeArray, ?context : LDContext) = + let id = match id with + | Some id -> id + | None -> Sample.genIDSample name + let s = Sample.create(id, name, ?additionalProperties = additionalProperties, ?context = context) + s.AdditionalType <- ResizeArray ["Sample"] + s + + static member createSource (name : string, ?id : string, ?additionalProperties : ResizeArray, ?context : LDContext) = + let id = match id with + | Some id -> id + | None -> Sample.genIDSource name + let s = Sample.create(id, name, ?additionalProperties = additionalProperties, ?context = context) + s.AdditionalType <- ResizeArray ["Source"] + s + + static member createMaterial (name : string, ?id, ?additionalProperties : ResizeArray, ?context : LDContext) = + let id = match id with + | Some id -> id + | None -> Sample.genIDMaterial name + let s = Sample.create(id, name, ?additionalProperties = additionalProperties, ?context = context) + s.AdditionalType <- ResizeArray ["Material"] + s \ No newline at end of file diff --git a/src/ROCrate/Generic/ScholarlyArticle.fs b/src/ROCrate/Generic/ScholarlyArticle.fs new file mode 100644 index 00000000..a3985283 --- /dev/null +++ b/src/ROCrate/Generic/ScholarlyArticle.fs @@ -0,0 +1,103 @@ +namespace ARCtrl.ROCrate + +open DynamicObj +open Fable.Core +open ARCtrl.ROCrate +/// + +[] +type ScholarlyArticle = + + static member schemaType = "http://schema.org/ScholarlyArticle" + + static member headline = "http://schema.org/headline" + + static member identifier = "http://schema.org/identifier" + + static member author = "http://schema.org/author" + + static member url = "http://schema.org/url" + + static member creativeWorkStatus = "http://schema.org/creativeWorkStatus" + + static member comment = "http://schema.org/comment" + + static member tryGetHeadlineAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(ScholarlyArticle.headline, ?context = context) with + | Some (:? string as n) -> Some n + | _ -> None + + static member getHeadlineAsString(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(ScholarlyArticle.headline, ?context = context) with + | Some (:? string as n) -> n + | Some _ -> failwith $"Value of property `headline` of object with @id `{s.Id}` should have been a string" + | None -> failwith $"Could not access property `headline` of object with @id `{s.Id}`" + + static member setHeadlineAsString(s : LDNode, n : string) = + s.SetProperty(ScholarlyArticle.headline, n) + + static member getIdentifiers(s : LDNode, ?context : LDContext) = + s.GetPropertyValues(ScholarlyArticle.identifier, ?context = context) + + static member getIdentifiersAsPropertyValue(s : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter = fun ldObject context -> PropertyValue.validate(ldObject, ?context = context) + s.GetPropertyNodes(ScholarlyArticle.identifier, filter = filter, ?graph = graph, ?context = context) + + static member setIdentifiers(s : LDNode, identifiers : ResizeArray) = + s.SetProperty(ScholarlyArticle.identifier, identifiers) + + static member getAuthors(s : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter ldObject context = Person.validate(ldObject, ?context = context) + s.GetPropertyNodes(ScholarlyArticle.author, filter = filter, ?graph = graph, ?context = context) + + static member setAuthors(s : LDNode, authors : ResizeArray, ?context : LDContext) = + s.SetProperty(ScholarlyArticle.author, authors, ?context = context) + + static member tryGetUrl(s : LDNode, ?context : LDContext) = + match s.TryGetPropertyAsSingleton(ScholarlyArticle.url, ?context = context) with + | Some (:? string as u) -> Some u + | _ -> None + + static member setUrl(s : LDNode, u : string, ?context : LDContext) = + s.SetProperty(ScholarlyArticle.url, u, ?context = context) + + static member tryGetCreativeWorkStatus(s : LDNode, ?graph : LDGraph, ?context : LDContext) = + match s.TryGetPropertyAsSingleNode(ScholarlyArticle.creativeWorkStatus, ?graph = graph, ?context = context) with + | Some cws when DefinedTerm.validate cws -> Some cws + | _ -> None + + static member setCreativeWorkStatus(s : LDNode, cws : LDNode, ?context : LDContext) = + s.SetProperty(ScholarlyArticle.creativeWorkStatus, cws, ?context = context) + + static member getComments(s : LDNode, ?graph : LDGraph, ?context : LDContext) = + let filter = fun ldObject context -> Comment.validate(ldObject, ?context = context) + s.GetPropertyNodes(ScholarlyArticle.comment, filter = filter, ?graph = graph, ?context = context) + + static member setcomments(s : LDNode, comments : ResizeArray, ?context : LDContext) = + s.SetProperty(ScholarlyArticle.comment, comments, ?context = context) + + static member genID(headline : string, ?url : string) = + match url with + | Some u -> u + | None -> $"#{headline}" + |> Helper.ID.clean + + static member validate(s : LDNode, ?context : LDContext) = + s.HasType(ScholarlyArticle.schemaType, ?context = context) + && s.HasProperty(ScholarlyArticle.headline, ?context = context) + //&& s.HasProperty(ScholarlyArticle.identifier, ?context = context) + + static member create(headline : string, identifiers : ResizeArray<#obj>, ?id : string, ?authors : ResizeArray, ?url : string, ?creativeWorkStatus : LDNode, ?comments : ResizeArray, ?context : LDContext) = + let id = match id with + | Some i -> i + | None -> ScholarlyArticle.genID(headline, ?url = url) + let s = LDNode(id, ResizeArray [ScholarlyArticle.schemaType], ?context = context) + s.SetProperty(ScholarlyArticle.headline, headline, ?context = context) + s.SetProperty(ScholarlyArticle.identifier, identifiers, ?context = context) + s.SetOptionalProperty(ScholarlyArticle.author, authors, ?context = context) + s.SetOptionalProperty(ScholarlyArticle.url, url, ?context = context) + s.SetOptionalProperty(ScholarlyArticle.creativeWorkStatus, creativeWorkStatus, ?context = context) + s.SetOptionalProperty(ScholarlyArticle.comment, comments, ?context = context) + s + + \ No newline at end of file diff --git a/src/ROCrate/Helper.fs b/src/ROCrate/Helper.fs new file mode 100644 index 00000000..6ff35b06 --- /dev/null +++ b/src/ROCrate/Helper.fs @@ -0,0 +1,6 @@ +module ARCtrl.ROCrate.Helper + +module ID = + + let clean (id : string) = + id.Replace(" ", "_") \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/Assay.fs b/src/ROCrate/ISAProfile/Assay.fs deleted file mode 100644 index 5532ada4..00000000 --- a/src/ROCrate/ISAProfile/Assay.fs +++ /dev/null @@ -1,34 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Assay( - id: string, - identifier: string, - ?about, - ?comment, - ?creator, - ?hasPart, - ?measurementMethod, - ?measurementTechnique, - ?url, - ?variableMeasured -) as this = - inherit Dataset(id, "Assay") - do - DynObj.setProperty (nameof identifier) identifier this - - DynObj.setOptionalProperty (nameof measurementMethod) measurementMethod this - DynObj.setOptionalProperty (nameof measurementTechnique) measurementTechnique this - DynObj.setOptionalProperty (nameof variableMeasured) variableMeasured this - DynObj.setOptionalProperty (nameof about) about this - DynObj.setOptionalProperty (nameof comment) comment this - DynObj.setOptionalProperty (nameof creator) creator this - DynObj.setOptionalProperty (nameof hasPart) hasPart this - DynObj.setOptionalProperty (nameof url) url this - - member this.GetIdentifier() = DynObj.getMandatoryDynamicPropertyOrThrow "Assay" (nameof identifier) this - static member getIdentifier = fun (ass: Assay) -> ass.GetIdentifier() \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/Data.fs b/src/ROCrate/ISAProfile/Data.fs deleted file mode 100644 index 1f4e30ec..00000000 --- a/src/ROCrate/ISAProfile/Data.fs +++ /dev/null @@ -1,25 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Data( - id, - name, - ?additionalType, - ?comment, - ?encodingFormat, - ?disambiguatingDescription -) as this = - inherit LDObject(id = id, schemaType = "schema.org/MediaObject", ?additionalType = additionalType) - do - DynObj.setProperty (nameof name) name this - - DynObj.setOptionalProperty (nameof comment) comment this - DynObj.setOptionalProperty (nameof encodingFormat) encodingFormat this - DynObj.setOptionalProperty (nameof disambiguatingDescription) disambiguatingDescription this - - member this.GetName() = DynObj.getMandatoryDynamicPropertyOrThrow "Data" (nameof name) this - static member getName = fun (d: Data) -> d.GetName() \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/Dataset.fs b/src/ROCrate/ISAProfile/Dataset.fs deleted file mode 100644 index 52ce4779..00000000 --- a/src/ROCrate/ISAProfile/Dataset.fs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Dataset (id: string, ?additionalType: string) = - inherit LDObject(id = id, schemaType = "schema.org/Dataset", ?additionalType = additionalType) diff --git a/src/ROCrate/ISAProfile/Investigation.fs b/src/ROCrate/ISAProfile/Investigation.fs deleted file mode 100644 index 8e08aff7..00000000 --- a/src/ROCrate/ISAProfile/Investigation.fs +++ /dev/null @@ -1,40 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Investigation( - id: string, - identifier: string, - ?citation, - ?comment, - ?creator, - ?dateCreated, - ?dateModified, - ?datePublished, - ?hasPart, - ?headline, - ?mentions, - ?url, - ?description -) as this = - inherit Dataset(id, "Investigation") - do - DynObj.setProperty (nameof identifier) identifier this - - DynObj.setOptionalProperty (nameof citation) citation this - DynObj.setOptionalProperty (nameof comment) comment this - DynObj.setOptionalProperty (nameof creator) creator this - DynObj.setOptionalProperty (nameof dateCreated) dateCreated this - DynObj.setOptionalProperty (nameof dateModified) dateModified this - DynObj.setOptionalProperty (nameof datePublished) datePublished this - DynObj.setOptionalProperty (nameof hasPart) hasPart this - DynObj.setOptionalProperty (nameof headline) headline this - DynObj.setOptionalProperty (nameof mentions) mentions this - DynObj.setOptionalProperty (nameof url) url this - DynObj.setOptionalProperty (nameof description) description this - - member this.GetIdentifier() = DynObj.getMandatoryDynamicPropertyOrThrow "Investigation" (nameof identifier) this - static member getIdentifier = fun (inv: Investigation) -> inv.GetIdentifier() \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/LabProcess.fs b/src/ROCrate/ISAProfile/LabProcess.fs deleted file mode 100644 index 9abb4fdc..00000000 --- a/src/ROCrate/ISAProfile/LabProcess.fs +++ /dev/null @@ -1,42 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type LabProcess( - id: string, - name, - agent, - object, - result, - ?additionalType, - ?executesLabProtocol, - ?parameterValue, - ?endTime, - ?disambiguatingDescription -) as this = - inherit LDObject(id = id, schemaType = "bioschemas.org/LabProcess", ?additionalType = additionalType) - do - DynObj.setProperty (nameof name) name this - DynObj.setProperty (nameof agent) agent this - DynObj.setProperty (nameof object) object this - DynObj.setProperty (nameof result) result this - - DynObj.setOptionalProperty (nameof executesLabProtocol) executesLabProtocol this - DynObj.setOptionalProperty (nameof parameterValue) parameterValue this - DynObj.setOptionalProperty (nameof endTime) endTime this - DynObj.setOptionalProperty (nameof disambiguatingDescription) disambiguatingDescription this - - member this.GetName() = DynObj.getMandatoryDynamicPropertyOrThrow "LabProcess" (nameof name) this - static member getName = fun (lp: LabProcess) -> lp.GetName() - - member this.GetAgent() = DynObj.getMandatoryDynamicPropertyOrThrow "LabProcess" (nameof agent) this - static member getAgent = fun (lp: LabProcess) -> lp.GetAgent() - - member this.GetObject() = DynObj.getMandatoryDynamicPropertyOrThrow "LabProcess" (nameof object) this - static member getObject = fun (lp: LabProcess) -> lp.GetObject() - - member this.GetResult() = DynObj.getMandatoryDynamicPropertyOrThrow "LabProcess" (nameof result) this - static member getResult = fun (lp: LabProcess) -> lp.GetResult() diff --git a/src/ROCrate/ISAProfile/LabProtocol.fs b/src/ROCrate/ISAProfile/LabProtocol.fs deleted file mode 100644 index db6a66d4..00000000 --- a/src/ROCrate/ISAProfile/LabProtocol.fs +++ /dev/null @@ -1,31 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type LabProtocol( - id, - ?additionalType, - ?name, - ?intendedUse, - ?description, - ?url, - ?comment, - ?version, - ?labEquipment, - ?reagent, - ?computationalTool -) as this = - inherit LDObject(id = id, schemaType = "bioschemas.org/LabProtocol", ?additionalType = additionalType) - do - DynObj.setOptionalProperty (nameof name) name this - DynObj.setOptionalProperty (nameof intendedUse) intendedUse this - DynObj.setOptionalProperty (nameof description) description this - DynObj.setOptionalProperty (nameof url) url this - DynObj.setOptionalProperty (nameof comment) comment this - DynObj.setOptionalProperty (nameof version) version this - DynObj.setOptionalProperty (nameof labEquipment) labEquipment this - DynObj.setOptionalProperty (nameof reagent) reagent this - DynObj.setOptionalProperty (nameof computationalTool) computationalTool this diff --git a/src/ROCrate/ISAProfile/Person.fs b/src/ROCrate/ISAProfile/Person.fs deleted file mode 100644 index b3076813..00000000 --- a/src/ROCrate/ISAProfile/Person.fs +++ /dev/null @@ -1,40 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Person( - id, - givenName, - ?additionalType, - ?familyName, - ?email, - ?identifier, - ?affiliation, - ?jobTitle, - ?additionalName, - ?address, - ?telephone, - ?faxNumber, - ?disambiguatingDescription -) as this= - inherit LDObject(id = id, schemaType = "schema.org/Person", ?additionalType = additionalType) - do - - DynObj.setProperty (nameof givenName) givenName this - - DynObj.setOptionalProperty (nameof familyName) familyName this - DynObj.setOptionalProperty (nameof email) email this - DynObj.setOptionalProperty (nameof identifier) identifier this - DynObj.setOptionalProperty (nameof affiliation) affiliation this - DynObj.setOptionalProperty (nameof jobTitle) jobTitle this - DynObj.setOptionalProperty (nameof additionalName) additionalName this - DynObj.setOptionalProperty (nameof address) address this - DynObj.setOptionalProperty (nameof telephone) telephone this - DynObj.setOptionalProperty (nameof faxNumber) faxNumber this - DynObj.setOptionalProperty (nameof disambiguatingDescription) disambiguatingDescription this - - member this.GetGivenName() = DynObj.getMandatoryDynamicPropertyOrThrow "Person" (nameof givenName) this - static member getGivenName = fun (p: Person) -> p.GetGivenName() \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/PropertyValue.fs b/src/ROCrate/ISAProfile/PropertyValue.fs deleted file mode 100644 index 730ad7a7..00000000 --- a/src/ROCrate/ISAProfile/PropertyValue.fs +++ /dev/null @@ -1,33 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type PropertyValue( - id, - name, - value, - ?propertyID, - ?unitCode, - ?unitText, - ?valueReference, - ?additionalType -) as this = - inherit LDObject(id = id, schemaType = "schema.org/PropertyValue", ?additionalType = additionalType) - do - - DynObj.setProperty (nameof name) name this - DynObj.setProperty (nameof value) value this - - DynObj.setOptionalProperty (nameof propertyID) propertyID this - DynObj.setOptionalProperty (nameof unitCode) unitCode this - DynObj.setOptionalProperty (nameof unitText) unitText this - DynObj.setOptionalProperty (nameof valueReference) valueReference this - - member this.GetName() = DynObj.getMandatoryDynamicPropertyOrThrow "PropertyValue" (nameof name) this - static member getName = fun (lp: PropertyValue) -> lp.GetName() - - member this.GetValue() = DynObj.getMandatoryDynamicPropertyOrThrow "PropertyValue" (nameof name) this - static member getValue = fun (lp: PropertyValue) -> lp.GetValue() diff --git a/src/ROCrate/ISAProfile/Sample.fs b/src/ROCrate/ISAProfile/Sample.fs deleted file mode 100644 index a607ce56..00000000 --- a/src/ROCrate/ISAProfile/Sample.fs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Sample( - id, - name, - ?additionalType, - ?additionalProperty, - ?derivesFrom -) as this = - inherit LDObject(id = id, schemaType = "bioschemas.org/Sample", ?additionalType = additionalType) - do - DynObj.setProperty (nameof name) name this - - DynObj.setOptionalProperty (nameof additionalProperty) additionalProperty this - DynObj.setOptionalProperty (nameof derivesFrom) derivesFrom this - - member this.GetName() = DynObj.getMandatoryDynamicPropertyOrThrow "Sample" (nameof name) this - static member getName = fun (s: Sample) -> s.GetName() diff --git a/src/ROCrate/ISAProfile/ScholarlyArticle.fs b/src/ROCrate/ISAProfile/ScholarlyArticle.fs deleted file mode 100644 index cb4905a5..00000000 --- a/src/ROCrate/ISAProfile/ScholarlyArticle.fs +++ /dev/null @@ -1,34 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type ScholarlyArticle( - id, - headline, - identifier, - ?additionalType, - ?author, - ?url, - ?creativeWorkStatus, - ?disambiguatingDescription - -) as this = - inherit LDObject(id = id, schemaType = "schema.org/ScholarlyArticle", ?additionalType = additionalType) - do - - DynObj.setProperty (nameof headline) headline this - DynObj.setProperty (nameof identifier) identifier this - - DynObj.setOptionalProperty (nameof author) author this - DynObj.setOptionalProperty (nameof url) url this - DynObj.setOptionalProperty (nameof creativeWorkStatus) creativeWorkStatus this - DynObj.setOptionalProperty (nameof disambiguatingDescription) disambiguatingDescription this - - member this.GetHeadline() = DynObj.getMandatoryDynamicPropertyOrThrow "ScholarlyArticle" (nameof headline) this - static member getHeadline = fun (s: ScholarlyArticle) -> s.GetHeadline() - - member this.GetIdentifier() = DynObj.getMandatoryDynamicPropertyOrThrow "ScholarlyArticle" (nameof identifier) this - static member getIdentifier = fun (s: ScholarlyArticle) -> s.GetIdentifier() \ No newline at end of file diff --git a/src/ROCrate/ISAProfile/Study.fs b/src/ROCrate/ISAProfile/Study.fs deleted file mode 100644 index 41bbd82e..00000000 --- a/src/ROCrate/ISAProfile/Study.fs +++ /dev/null @@ -1,39 +0,0 @@ -namespace ARCtrl.ROCrate - -open DynamicObj -open Fable.Core - -/// -[] -type Study( - id: string, - identifier: string, - ?about, - ?citation, - ?comment, - ?creator, - ?dateCreated, - ?dateModified, - ?datePublished, - ?description, - ?hasPart, - ?headline, - ?url -) as this = - inherit Dataset(id, "Study") - do - DynObj.setProperty (nameof identifier) identifier this - DynObj.setOptionalProperty (nameof about) about this - DynObj.setOptionalProperty (nameof citation) citation this - DynObj.setOptionalProperty (nameof comment) comment this - DynObj.setOptionalProperty (nameof creator) creator this - DynObj.setOptionalProperty (nameof dateCreated) dateCreated this - DynObj.setOptionalProperty (nameof dateModified) dateModified this - DynObj.setOptionalProperty (nameof datePublished) datePublished this - DynObj.setOptionalProperty (nameof description) description this - DynObj.setOptionalProperty (nameof hasPart) hasPart this - DynObj.setOptionalProperty (nameof headline) headline this - DynObj.setOptionalProperty (nameof url) url this - - member this.GetIdentifier() = DynObj.getMandatoryDynamicPropertyOrThrow "Study" (nameof identifier) this - static member getIdentifier = fun (inv: Investigation) -> inv.GetIdentifier() diff --git a/src/ROCrate/LDContext.fs b/src/ROCrate/LDContext.fs new file mode 100644 index 00000000..98284efc --- /dev/null +++ b/src/ROCrate/LDContext.fs @@ -0,0 +1,219 @@ +namespace ARCtrl.ROCrate + +open System.Collections.Generic +open ARCtrl.Helper +open Fable.Core + +module Dictionary = + + let ofSeq (s : seq<'Key*'T>) = + let dict = Dictionary() + s + |> Seq.iter dict.Add + dict + + let tryFind (key : 'Key) (dict : Dictionary<'Key,'T>) = + let b,v = dict.TryGetValue key + if b then Some v + else None + +module IRIHelper = + + open ARCtrl.Helper.Regex + + let compactIRIRegex = """(?.*):(?[^\/][^\/].*)""" + + let (|CompactIri|_|) (termDefition : string) = + match termDefition with + | ActivePatterns.Regex compactIRIRegex result -> + let prefix = result.Groups.["prefix"].Value + let suffix = result.Groups.["suffix"].Value + Some(prefix,suffix) + | _ -> None + + let combine (baseIRI : string) (relative : string) = + if relative.StartsWith("http://") || relative.StartsWith("https://") then + relative + else + let baseUri = new System.Uri(baseIRI) + let relativeUri = new System.Uri(baseUri,relative) + relativeUri.ToString() + + let combineOptional (baseIRI : string option) (relative : string option) = + match baseIRI, relative with + | Some b, Some r -> Some (combine b r) + | Some b, None -> Some b + | None, Some r -> Some r + | _ -> None + +// Add second dictionary which maps from definition to term? +// Make LDContext to be nested hierarchical tree? Like this you can iterate through the tree and stop at the first match, kind of like a shadowing mechanism +[] +type LDContext(?mappings : Dictionary, ?baseContexts : ResizeArray) = + + let mutable baseContexts = Option.defaultValue (ResizeArray []) baseContexts + let mutable name : string option = None + + /// Dictionary + let mappings : Dictionary = + match mappings with + | Some m -> m + | None -> Dictionary() + + /// Dictionary + let reverseMappings : Dictionary = Dictionary() + + /// Dictionary + let compactReverseMappings : Dictionary = Dictionary() + + let addReverseMapping (key : string) (value : string) = + Dictionary.addOrUpdate value key reverseMappings + match value with + | IRIHelper.CompactIri (prefix,suffix) -> + Dictionary.addOrUpdate prefix (suffix,key) compactReverseMappings + match Dictionary.tryFind prefix mappings with + | Some prefix -> + let iri = IRIHelper.combine prefix suffix + Dictionary.addOrUpdate iri key reverseMappings + | None -> () + | _ -> + match Dictionary.tryFind key compactReverseMappings with + | Some (suffix,term) -> + let iri = IRIHelper.combine value suffix + Dictionary.addOrUpdate iri term reverseMappings + | None -> () + + do for kvp in mappings do + addReverseMapping kvp.Key kvp.Value + + let rec tryFindTerm (term : string) : string option = + let definition = + match Dictionary.tryFind term mappings with + | Some v -> Some v + | None -> + baseContexts + |> Seq.tryPick (fun ctx -> ctx.TryResolveTerm term) + match definition with + | Some (IRIHelper.CompactIri (prefix,suffix)) -> + let prefix = if prefix = term then prefix else tryFindTerm prefix |> Option.defaultValue prefix + let suffix = if suffix = term then suffix else tryFindTerm suffix |> Option.defaultValue suffix + IRIHelper.combine prefix suffix + |> Some + | Some d -> Some d + | None -> None + + let tryFindIri (iri : string) = + match Dictionary.tryFind iri reverseMappings with + | Some v -> Some v + | None -> + baseContexts + |> Seq.tryPick (fun ctx -> ctx.TryGetTerm iri) + + let tryCompactIRI (iri : string) = + failwith "TryCompactIRI is Not implemented yet" + + member this.Mappings + with get() = mappings + + member this.BaseContexts + with get() = baseContexts + and internal set(value) = baseContexts <- value + + member this.Name + with get() = name + and set(value) = name <- value + + member this.AddMapping(term,definition) = + Dictionary.addOrUpdate term definition mappings + addReverseMapping term definition + + member this.TryResolveTerm(term : string) = + // Handle compact IRI + if term.Contains(":") then + term.Split(':') + |> Seq.map tryFindTerm + |> Seq.reduce IRIHelper.combineOptional + else + tryFindTerm term + + member this.TryGetTerm(iri : string) = + tryFindIri iri + + member this.PropertyNamesMatch(p1 : string,p2 : string) = + if p1 = p2 then true + else + let p1Def = this.TryResolveTerm p1 + let p2Def = this.TryResolveTerm p2 + match p1Def,p2Def with + | Some p1Def, Some p2Def -> p1Def = p2Def + | Some p1Def, None -> p1Def = p2 + | None, Some p2Def -> p1 = p2Def + | _ -> false + + static member fromMappingSeq(mappings : seq) = + LDContext(Dictionary.ofSeq mappings) + + // Append second context to the first one inplace + static member combine_InPlace (first : LDContext) (second : LDContext) : LDContext = + first.BaseContexts.Add second + first + + // Create new context with the the two given contexts as baseContexts + static member combine (first : LDContext) (second : LDContext) : LDContext = + LDContext(baseContexts = ResizeArray([first;second])) + + static member tryCombineOptional (first : LDContext option) (second : LDContext option) : LDContext option = + match first,second with + | Some f, Some s -> Some (LDContext.combine f s) + | Some f, None -> Some f + | None, Some s -> Some s + | _ -> None + + member this.ShallowCopy() = + let newMappings = Dictionary() + for kvp in mappings do + newMappings.Add(kvp.Key,kvp.Value) + LDContext(mappings = newMappings, baseContexts = baseContexts) + + member this.DeepCopy() = + let newMappings = Dictionary() + for kvp in mappings do + newMappings.Add(kvp.Key,kvp.Value) + let newBaseContexts = ResizeArray() + for ctx in baseContexts do + newBaseContexts.Add(ctx.DeepCopy()) + LDContext(mappings = newMappings, baseContexts = newBaseContexts) + + interface System.ICloneable with + member this.Clone() = + this.DeepCopy() + + member this.StructurallyEquals(other : LDContext) = + this.GetHashCode() = other.GetHashCode() + + member this.ReferenceEquals(other : LDContext) = + System.Object.ReferenceEquals(this,other) + + override this.Equals(other : obj) = + match other with + | :? LDContext as other -> this.StructurallyEquals(other) + | _ -> false + + override this.GetHashCode() = + let mappingsHash = + this.Mappings.Keys + |> Seq.sort + |> Seq.map (fun k -> HashCodes.mergeHashes (HashCodes.hash k) (HashCodes.hash this.Mappings.[k])) + |> HashCodes.boxHashSeq + |> fun v -> v :?> int + let nameHash = + match this.Name with + | Some n -> n.GetHashCode() + | None -> 0 + let baseContextsHash = + if baseContexts.Count = 0 then 0 + else + baseContexts + |> Seq.map (fun ctx -> ctx.GetHashCode()) + |> Seq.reduce HashCodes.mergeHashes + HashCodes.mergeHashes (HashCodes.mergeHashes mappingsHash nameHash) baseContextsHash \ No newline at end of file diff --git a/src/ROCrate/LDObject.fs b/src/ROCrate/LDObject.fs index bf001ba7..31708c05 100644 --- a/src/ROCrate/LDObject.fs +++ b/src/ROCrate/LDObject.fs @@ -5,22 +5,183 @@ open Thoth.Json.Core open Fable.Core open System -type LDContext() = inherit DynamicObj() +module ActivePattern = + #if !FABLE_COMPILER + let (|SomeObj|_|) = + // create generalized option type + let ty = typedefof> + fun (a:obj) -> + // Check for nulls otherwise 'a.GetType()' would fail + if isNull a + then + None + else + let aty = a.GetType() + // Get option'.Value + let v = aty.GetProperty("Value") + if aty.IsGenericType && aty.GetGenericTypeDefinition() = ty then + // return value if existing + Some(v.GetValue(a, [| |])) + else + None + #endif + let (|NonStringEnumerable|_|) (o : obj) = + match o with + | :? string as s -> None + | :? System.Collections.IEnumerable as e -> Some e + | _ -> None + + + + +[] +module DynamicObjExtensions = + + type DynamicObj with + + member this.HasProperty(propertyName : string) = + this.TryGetPropertyValue(propertyName) |> Option.isSome /// Base interface implemented by all explicitly known objects in our ROCrate profiles. type ILDObject = - abstract member SchemaType : string with get, set + abstract member SchemaType : ResizeArray with get, set abstract member Id: string - abstract member AdditionalType: string option with get, set + abstract member AdditionalType: ResizeArray with get, set -/// Base class for all explicitly known objects in our ROCrate profiles to inherit from. -/// Basically a DynamicObj that implements the ILDObject interface. [] -type LDObject(id:string, schemaType: string, ?additionalType) = +type LDValue(value : obj, ?valueType : string) = + + let mutable valueType = defaultArg valueType "string" + let mutable value = value + + member this.Value + with get() = value + and set(v) = value <- v + + member this.ValueType + with get() = valueType + and set(v) = valueType <- v + + override this.Equals(other : obj) = + match other with + | :? LDValue as other -> + this.Value = other.Value + | _ -> false + + override this.GetHashCode() = + HashCodes.mergeHashes (123) (this.Value.GetHashCode()) + +and [] LDRef(id : string) = + let mutable id = id + + member this.Id + with get() = id + and set(v) = id <- v + + override this.Equals(other : obj) = + match other with + | :? LDRef as other -> + this.Id = other.Id + | _ -> false + + override this.GetHashCode() = + HashCodes.mergeHashes (123) (this.Id.GetHashCode()) + +and [] LDGraph(?id : string, ?nodes : ResizeArray, ?context : LDContext) as this = + + inherit DynamicObj() + + let mutable id = id + let mappings = System.Collections.Generic.Dictionary() + + do + match context with + | Some ctx -> this.SetContext(ctx) + | None -> () + + do + match nodes with + | Some nodes -> + nodes + |> Seq.iter (fun node -> + mappings.Add(node.Id, node) + ) + | None -> () + + member this.Id + with get() = id + and set(v) = id <- v + + member this.Nodes + with get() = mappings.Values |> ResizeArray + + member this.ContainsNode(id : string) = + mappings.ContainsKey(id) + + member this.GetNode(id : string) = + mappings.Item(id) + + member this.TryGetNode(id : string) = + match mappings.TryGetValue(id) with + | true, node -> Some node + | _ -> None + + member this.AddNode(node : LDNode) = + let id = node.Id + match this.TryGetNode(id) with + | Some existingNode -> node.MergeAppendInto_InPlace(existingNode, flattenTo = this) + | None -> mappings.Add(id, node) + + member this.Compact_InPlace(?context : LDContext) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + this.Nodes + |> Seq.iter (fun node -> node.Compact_InPlace(?context = context)) + + member this.SetContext (context: LDContext) = + this.SetProperty("@context", context) + + static member setContext (context: LDContext) = fun (roc: #LDNode) -> roc.SetContext(context) + + member this.TryGetContext() = DynObj.tryGetTypedPropertyValue("@context") this + + static member tryGetContext () = fun (roc: #LDNode) -> roc.TryGetContext() + + member this.RemoveContext() = this.RemoveProperty("@context") + + member this.GetDynamicPropertyHelpers() = + + this.GetPropertyHelpers(false) + |> Seq.filter (fun ph -> + (ph.Name.StartsWith "init@" || ph.Name.Equals("mappings")) + |> not + ) + + member this.GetDynamicPropertyNames(?context : LDContext) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + this.GetDynamicPropertyHelpers() + |> Seq.choose (fun ph -> + let name = + match context with + | Some ctx -> + match ctx.TryResolveTerm ph.Name with + | Some term -> term + | None -> ph.Name + | None -> ph.Name + if name = "@context" then None else Some name + ) + +/// Base class for all explicitly known objects in our ROCrate profiles to inherit from. +/// Basically a DynamicObj that implements the ILDNode interface. +and [] LDNode(id: string, schemaType: ResizeArray, ?additionalType: ResizeArray, ?context : LDContext) as this = inherit DynamicObj() let mutable schemaType = schemaType - let mutable additionalType = additionalType + let mutable additionalType = defaultArg additionalType (ResizeArray []) + + do + match context with + | Some ctx -> this.SetContext(ctx) + | None -> () member this.Id with get() = id @@ -33,27 +194,417 @@ type LDObject(id:string, schemaType: string, ?additionalType) = with get() = additionalType and set(value) = additionalType <- value - interface ILDObject with + member this.HasType(schemaType:string, ?context : LDContext) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + this.SchemaType + |> Seq.exists (fun st -> + if st = schemaType then true + else + match context with + | Some ctx -> + match ctx.TryResolveTerm st, ctx.TryResolveTerm schemaType with + | Some st, Some schemaType -> st = schemaType + | Some st, None -> st = schemaType + | None, Some schemaType -> st = schemaType + | _ -> false + | None -> false + ) + + member this.TryGetProperty(propertyName : string, ?context : LDContext) = + match this.TryGetPropertyValue(propertyName) with + | Some value -> Some value + | None -> + match LDContext.tryCombineOptional context (this.TryGetContext()) with + | Some ctx -> + match ctx.TryResolveTerm propertyName with + | Some term -> this.TryGetPropertyValue term + | None -> + // Or instead of compact search term + match ctx.TryGetTerm propertyName with + | Some term -> this.TryGetPropertyValue term + | None -> None + | None -> None + + member this.TryGetPropertyAsSingleton(propertyName : string, ?context : LDContext) : obj option = + match this.TryGetProperty(propertyName, ?context = context) with + | Some (:? string as s) -> Some s + | Some (:? System.Collections.IEnumerable as e) -> + let en = e.GetEnumerator() + if en.MoveNext() then Some en.Current else None + | Some o -> Some o + | _ -> None + + member this.GetPropertyValues(propertyName : string, ?filter : obj -> LDContext option -> bool, ?context) = + let filter = defaultArg filter (fun _ _ -> true) + match this.TryGetProperty(propertyName, ?context = context) with + | Some (:? string as s) -> + if filter s context then + ResizeArray [box s] + else + ResizeArray [] + | Some (:? System.Collections.IEnumerable as e) -> + let en = e.GetEnumerator() + [ + while en.MoveNext() do + if filter en.Current context then + yield en.Current + ] + |> ResizeArray + | Some o when filter o context-> + ResizeArray [o] + | _ -> + ResizeArray [] + + member this.TryGetPropertyAsSingleNode(propertyName : string, ?graph : LDGraph, ?context : LDContext) = + match this.TryGetPropertyAsSingleton(propertyName, ?context = context) with + | Some (:? LDNode as n) -> Some n + | Some (:? LDRef as r) when graph.IsSome -> + match graph.Value.TryGetNode(r.Id) with + | Some n -> Some n + | None -> None + | _ -> None + + member this.GetPropertyNodes(propertyName : string, ?filter : LDNode -> LDContext option -> bool, ?graph : LDGraph, ?context) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + this.GetPropertyValues(propertyName, ?context = context) + |> Seq.choose (fun o -> + match o with + | :? LDRef as r when graph.IsSome -> + match graph.Value.TryGetNode(r.Id) with + | Some n -> + match filter with + | Some f when f n context -> Some n + | None -> Some n + | _ -> None + | None -> None + | :? LDNode as n -> + match filter with + | Some f when f n context -> Some n + | None -> Some n + | _ -> None + | _ -> None + + ) + |> ResizeArray - member this.SchemaType - with get() = schemaType - and set(value) = schemaType <- value + member this.GetDynamicPropertyHelpers() = + this.GetPropertyHelpers(false) + |> Seq.filter (fun ph -> + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + (ph.Name.StartsWith "init@" || ph.Name.Equals("id")) + |> not + #endif + #if FABLE_COMPILER_PYTHON + (ph.Name.StartsWith "init_" || ph.Name.Equals("id")) + |> not + #endif + #if !FABLE_COMPILER + true + #endif + ) - member this.Id = id + member this.GetPropertyNames(?context : LDContext) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + this.GetDynamicPropertyHelpers() + |> Seq.choose (fun ph -> + let name = + match context with + | Some ctx -> + match ctx.TryResolveTerm ph.Name with + | Some term -> term + | None -> ph.Name + | None -> ph.Name + if name = "@context" then None else Some name + ) - member this.AdditionalType - with get() = additionalType - and set(value) = additionalType <- value + member this.SetProperty(propertyName : string, value : obj, ?context : LDContext) = + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + let propertyName = + this.GetPropertyNames() + |> Seq.tryFind (fun pn -> + match context with + | Some c -> c.PropertyNamesMatch(pn,propertyName) + | None -> pn = propertyName + ) + |> Option.defaultValue propertyName + #if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT + Fable.Core.JsInterop.emitJsStatement (propertyName, value) "super.SetProperty($0,$1)" + #endif + #if FABLE_COMPILER_PYTHON + Fable.Core.PyInterop.emitPyStatement (propertyName, value) "super().SetProperty($0,$1)" + #endif + #if !FABLE_COMPILER + (this :> DynamicObj).SetProperty(propertyName, value) + #endif + //DynObj.setProperty propertyName value this + + member this.SetOptionalProperty(propertyName : string, value : #obj option, ?context : LDContext) = + match value with + | Some v -> this.SetProperty(propertyName, v, ?context = context) + | None -> () + //this.RemoveProperty(propertyName) |> ignore + //let propertyName = + // match LDContext.tryCombineOptional context (this.TryGetContext()) with + // | Some ctx -> + // match ctx.TryResolveTerm propertyName with + // | Some term -> term + // | None -> propertyName + // | None -> propertyName + //this.SetProperty(propertyName,value) + + member this.HasProperty(propertyName : string, ?context : LDContext) = + let v = this.TryGetProperty(propertyName, ?context = context) + match v with + | None -> false + | Some v when v = null -> false + //| Some (:? string as s) -> s <> "" // Caught by next rule? + | Some (:? System.Collections.IEnumerable as e) -> e.GetEnumerator().MoveNext() + | _ -> true member this.SetContext (context: LDContext) = this.SetProperty("@context", context) - static member setContext (context: LDContext) = fun (roc: #LDObject) -> roc.SetContext(context) + static member setContext (context: LDContext) = fun (roc: #LDNode) -> roc.SetContext(context) - member this.TryGetContext() = DynObj.tryGetTypedPropertyValue("@context") this + member this.TryGetContext() = DynObj.tryGetTypedPropertyValue("@context") this - static member tryGetContext () = fun (roc: #LDObject) -> roc.TryGetContext() + static member tryGetContext () = fun (roc: #LDNode) -> roc.TryGetContext() member this.RemoveContext() = this.RemoveProperty("@context") - static member removeContext () = fun (roc: #LDObject) -> roc.RemoveContext() \ No newline at end of file + member this.MergeAppendInto_InPlace(other : LDNode, ?flattenTo : LDGraph) = + let flattenTo_Singleton : obj -> obj = + match flattenTo with + | Some graph -> + let rec f (o : obj) : obj = + match o with + #if !FABLE_COMPILER + | ActivePattern.SomeObj o -> f o + #endif + | :? LDNode as n -> + n.Flatten(graph) |> ignore + LDRef(n.Id) + | _ -> o + f + | None -> Operators.id + let flattenTo_RA : ResizeArray -> ResizeArray= + match flattenTo with + | Some graph -> + ARCtrl.Helper.ResizeArray.map flattenTo_Singleton + | None -> Operators.id + let flattenToAny : obj -> obj = + match flattenTo with + | Some graph -> + let rec f (o : obj) : obj = + match o with + #if !FABLE_COMPILER + | ActivePattern.SomeObj o -> f o + #endif + | :? LDNode as n -> + n.Flatten(graph) |> ignore + LDRef(n.Id) + | ActivePattern.NonStringEnumerable e -> + [for v in e do f v] |> ResizeArray |> box + | _ -> o + f + | None -> Operators.id + let rec toEqualitor (o : obj) : obj = + match o with + #if !FABLE_COMPILER + | ActivePattern.SomeObj o -> toEqualitor o + #endif + | :? LDNode as n -> n.Id + | :? LDRef as r -> r.Id + | _ -> o + this.GetPropertyNames() + |> Seq.iter (fun pn -> + match other.TryGetProperty(pn) with + | Some otherVal -> + let thisVal = this.TryGetProperty(pn).Value + match (thisVal, otherVal) with + | ActivePattern.NonStringEnumerable e1, ActivePattern.NonStringEnumerable e2 -> + let l = + [ + for v in e2 do + v + for v in e1 do + v + ] + |> List.distinctBy toEqualitor + |> ResizeArray + |> flattenTo_RA + other.SetProperty(pn, l) + | ActivePattern.NonStringEnumerable theseVals, otherVal -> + let mutable isContained = false + let l = ResizeArray [ + for thisVal in theseVals do + if toEqualitor thisVal = toEqualitor otherVal then + isContained <- true + flattenTo_Singleton thisVal + else thisVal + ] + if not isContained then + l.Add(otherVal) + other.SetProperty(pn, l) + | thisVal, ActivePattern.NonStringEnumerable otherVals -> + let mutable isContained = false + let l = ResizeArray [ + for otherVal in otherVals do + if toEqualitor thisVal = toEqualitor otherVal then + isContained <- true + otherVal + ] + if not isContained then + l.Add(flattenTo_Singleton thisVal) + other.SetProperty(pn, l) + | thisVal, otherVal -> + if toEqualitor thisVal = toEqualitor otherVal then () + else + let l = ResizeArray [flattenTo_Singleton thisVal; otherVal] + other.SetProperty(pn, l) + | None -> + let v = this.TryGetProperty(pn).Value |> flattenToAny + other.SetProperty(pn, v) + + ) + + + + member this.Compact_InPlace(?context : LDContext,?setContext : bool) = + let setContext = defaultArg setContext false + let context = LDContext.tryCombineOptional context (this.TryGetContext()) + if context.IsSome then + let context = context.Value + if setContext then this.SetContext(context) + let newTypes = ResizeArray [ + for st in this.SchemaType do + match context.TryGetTerm st with + | Some term -> term + | None -> st + ] + this.SchemaType <- newTypes + let rec compactValue_inPlace (o : obj) : obj = + match o with + | :? LDNode as n -> + n.Compact_InPlace(?context = context) + n + | :? string as s -> + s + | :? System.Collections.IEnumerable as e -> + let en = e.GetEnumerator() + let l = ResizeArray [ + while en.MoveNext() do + compactValue_inPlace en.Current + ] + if l.Count = 1 then l.[0] else l + | :? LDValue as v -> v.Value + | x -> x + + this.GetDynamicPropertyHelpers() + |> Seq.iter (fun ph -> + let newKey = + match context with + | Some ctx -> + match ctx.TryGetTerm ph.Name with + | Some term -> Some term + | None -> None + | None -> None + let newValue = + compactValue_inPlace (ph.GetValue(this)) + match newKey with + | Some key when key <> ph.Name -> + this.RemoveProperty(ph.Name) |> ignore + this.SetProperty(key, newValue) + | _ -> ph.SetValue this newValue + ) + + member this.Flatten(?graph : LDGraph) : LDGraph = + //let graph, graphContext = + // match graph with + // | Some g -> g, g.TryGetContext() + // | None -> new LDGraph(?context = this.TryGetContext()), None + let graph = + match graph with + | Some g -> g + | None -> new LDGraph(?context = this.TryGetContext()) + let rec flattenValue (o : obj) : obj = + match o with + | :? LDNode as n -> + n.Flatten(graph) |> ignore + LDRef(n.Id) + | :? string as s -> s + | :? System.Collections.IEnumerable as e -> + let en = e.GetEnumerator() + let l = ResizeArray [ + while en.MoveNext() do + flattenValue en.Current + ] + l + | x -> x + this.GetDynamicPropertyHelpers() + |> Seq.iter (fun ph -> + let newValue = flattenValue (ph.GetValue(this)) + ph.SetValue this newValue + ) + graph.AddNode this + graph + + member this.Unflatten(graph : LDGraph) = + let rec unflattenValue (o : obj) : obj = + match o with + | :? LDRef as r -> + match graph.TryGetNode(r.Id) with + | Some n -> n + | None -> r + | :? LDNode as n -> + n.Unflatten(graph) + n + | :? System.Collections.IEnumerable as e -> + let en = e.GetEnumerator() + let l = ResizeArray [ + while en.MoveNext() do + unflattenValue en.Current + ] + l + | x -> x + this.GetDynamicPropertyHelpers() + |> Seq.iter (fun ph -> + let newValue = unflattenValue (ph.GetValue(this)) + ph.SetValue this newValue + ) + + static member removeContext () = fun (roc: #LDNode) -> roc.RemoveContext() + + static member tryFromDynamicObj (dynObj: DynamicObj) = + + let original_id = DynObj.tryGetTypedPropertyValue "@id" dynObj + let original_type = DynObj.tryGetTypedPropertyValueAsResizeArray "@type" dynObj + match original_id, original_type with + | (Some id), (Some st)-> + // initialize with extracted static members only + let at = DynObj.tryGetTypedPropertyValueAsResizeArray "additionalType" dynObj + let roc = new LDNode(id = id, schemaType = st, ?additionalType = at) + + // copy dynamic properties! + dynObj.DeepCopyPropertiesTo(roc, includeInstanceProperties = false) + + + // ----- Commented out as implementation has not been finalized ----- + //printfn "dynobj" + //dynObj.GetPropertyHelpers(true) + //|> Seq.iter (fun p -> printfn "isDynamic:%b, Name: %s" p.IsDynamic p.Name) + //printfn "roc" + //roc.GetPropertyHelpers(true) + //|> Seq.iter (fun p -> printfn "isDynamic:%b, Name: %s" p.IsDynamic p.Name) + //roc.TryGetDynamicPropertyHelper("@id").Value.RemoveValue() + //roc.TryGetDynamicPropertyHelper("@type").Value.RemoveValue() + //if at.IsSome then roc.TryGetDynamicPropertyHelper("additionalType").Value.RemoveValue() + + roc.GetDynamicPropertyHelpers() + |> Seq.iter (fun ph -> + if ph.IsDynamic && (ph.Name = "@id" || ph.Name = "@type" || ph.Name = "additionalType"(* || ph.Name = "id"*)) then + ph.RemoveValue(roc) + ) + Some roc + + | _ -> None \ No newline at end of file diff --git a/src/ROCrate/ROCrateContext.fs b/src/ROCrate/ROCrateContext.fs new file mode 100644 index 00000000..3dbf23aa --- /dev/null +++ b/src/ROCrate/ROCrateContext.fs @@ -0,0 +1,5587 @@ +namespace ARCtrl.ROCrate + +module Context = + + let termsV1_2DRAFT = + """ + "3DModel", "http://schema.org/3DModel" + "AMRadioChannel", "http://schema.org/AMRadioChannel" + "APIReference", "http://schema.org/APIReference" + "Abdomen", "http://schema.org/Abdomen" + "AboutPage", "http://schema.org/AboutPage" + "AcceptAction", "http://schema.org/AcceptAction" + "Accommodation", "http://schema.org/Accommodation" + "AccountingService", "http://schema.org/AccountingService" + "AchieveAction", "http://schema.org/AchieveAction" + "Action", "http://schema.org/Action" + "ActionAccessSpecification", "http://schema.org/ActionAccessSpecification" + "ActionStatusType", "http://schema.org/ActionStatusType" + "ActivateAction", "http://schema.org/ActivateAction" + "ActivationFee", "http://schema.org/ActivationFee" + "ActiveActionStatus", "http://schema.org/ActiveActionStatus" + "ActiveNotRecruiting", "http://schema.org/ActiveNotRecruiting" + "AddAction", "http://schema.org/AddAction" + "AdministrativeArea", "http://schema.org/AdministrativeArea" + "AdultEntertainment", "http://schema.org/AdultEntertainment" + "AdultOrientedEnumeration", "http://schema.org/AdultOrientedEnumeration" + "AdvertiserContentArticle", "http://schema.org/AdvertiserContentArticle" + "AerobicActivity", "http://schema.org/AerobicActivity" + "AggregateOffer", "http://schema.org/AggregateOffer" + "AggregateRating", "http://schema.org/AggregateRating" + "AgreeAction", "http://schema.org/AgreeAction" + "Airline", "http://schema.org/Airline" + "Airport", "http://schema.org/Airport" + "AlbumRelease", "http://schema.org/AlbumRelease" + "AlcoholConsideration", "http://schema.org/AlcoholConsideration" + "AlignmentObject", "http://schema.org/AlignmentObject" + "AllWheelDriveConfiguration", "http://schema.org/AllWheelDriveConfiguration" + "AllergiesHealthAspect", "http://schema.org/AllergiesHealthAspect" + "AllocateAction", "http://schema.org/AllocateAction" + "AmpStory", "http://schema.org/AmpStory" + "AmusementPark", "http://schema.org/AmusementPark" + "AnaerobicActivity", "http://schema.org/AnaerobicActivity" + "AnalysisNewsArticle", "http://schema.org/AnalysisNewsArticle" + "AnatomicalStructure", "http://schema.org/AnatomicalStructure" + "AnatomicalSystem", "http://schema.org/AnatomicalSystem" + "AndroidPlatform", "http://schema.org/AndroidPlatform" + "Anesthesia", "http://schema.org/Anesthesia" + "AnimalShelter", "http://schema.org/AnimalShelter" + "Answer", "http://schema.org/Answer" + "Apartment", "http://schema.org/Apartment" + "ApartmentComplex", "http://schema.org/ApartmentComplex" + "Appearance", "http://schema.org/Appearance" + "AppendAction", "http://schema.org/AppendAction" + "ApplyAction", "http://schema.org/ApplyAction" + "ApprovedIndication", "http://schema.org/ApprovedIndication" + "Aquarium", "http://schema.org/Aquarium" + "ArchiveComponent", "http://schema.org/ArchiveComponent" + "ArchiveOrganization", "http://schema.org/ArchiveOrganization" + "ArriveAction", "http://schema.org/ArriveAction" + "ArtGallery", "http://schema.org/ArtGallery" + "Artery", "http://schema.org/Artery" + "Article", "http://schema.org/Article" + "AskAction", "http://schema.org/AskAction" + "AskPublicNewsArticle", "http://schema.org/AskPublicNewsArticle" + "AssessAction", "http://schema.org/AssessAction" + "AssignAction", "http://schema.org/AssignAction" + "Atlas", "http://schema.org/Atlas" + "Attorney", "http://schema.org/Attorney" + "Audience", "http://schema.org/Audience" + "AudioObject", "http://schema.org/AudioObject" + "AudioObjectSnapshot", "http://schema.org/AudioObjectSnapshot" + "Audiobook", "http://schema.org/Audiobook" + "AudiobookFormat", "http://schema.org/AudiobookFormat" + "AuthoritativeLegalValue", "http://schema.org/AuthoritativeLegalValue" + "AuthorizeAction", "http://schema.org/AuthorizeAction" + "AutoBodyShop", "http://schema.org/AutoBodyShop" + "AutoDealer", "http://schema.org/AutoDealer" + "AutoPartsStore", "http://schema.org/AutoPartsStore" + "AutoRental", "http://schema.org/AutoRental" + "AutoRepair", "http://schema.org/AutoRepair" + "AutoWash", "http://schema.org/AutoWash" + "AutomatedTeller", "http://schema.org/AutomatedTeller" + "AutomotiveBusiness", "http://schema.org/AutomotiveBusiness" + "Ayurvedic", "http://schema.org/Ayurvedic" + "BackOrder", "http://schema.org/BackOrder" + "BackgroundNewsArticle", "http://schema.org/BackgroundNewsArticle" + "Bacteria", "http://schema.org/Bacteria" + "Bakery", "http://schema.org/Bakery" + "Balance", "http://schema.org/Balance" + "BankAccount", "http://schema.org/BankAccount" + "BankOrCreditUnion", "http://schema.org/BankOrCreditUnion" + "BarOrPub", "http://schema.org/BarOrPub" + "Barcode", "http://schema.org/Barcode" + "BasicIncome", "http://schema.org/BasicIncome" + "Beach", "http://schema.org/Beach" + "BeautySalon", "http://schema.org/BeautySalon" + "BedAndBreakfast", "http://schema.org/BedAndBreakfast" + "BedDetails", "http://schema.org/BedDetails" + "BedType", "http://schema.org/BedType" + "BefriendAction", "http://schema.org/BefriendAction" + "BenefitsHealthAspect", "http://schema.org/BenefitsHealthAspect" + "BikeStore", "http://schema.org/BikeStore" + "BioChemEntity", "http://schema.org/BioChemEntity" + "Blog", "http://schema.org/Blog" + "BlogPosting", "http://schema.org/BlogPosting" + "BloodTest", "http://schema.org/BloodTest" + "BoardingPolicyType", "http://schema.org/BoardingPolicyType" + "BoatReservation", "http://schema.org/BoatReservation" + "BoatTerminal", "http://schema.org/BoatTerminal" + "BoatTrip", "http://schema.org/BoatTrip" + "BodyMeasurementArm", "http://schema.org/BodyMeasurementArm" + "BodyMeasurementBust", "http://schema.org/BodyMeasurementBust" + "BodyMeasurementChest", "http://schema.org/BodyMeasurementChest" + "BodyMeasurementFoot", "http://schema.org/BodyMeasurementFoot" + "BodyMeasurementHand", "http://schema.org/BodyMeasurementHand" + "BodyMeasurementHead", "http://schema.org/BodyMeasurementHead" + "BodyMeasurementHeight", "http://schema.org/BodyMeasurementHeight" + "BodyMeasurementHips", "http://schema.org/BodyMeasurementHips" + "BodyMeasurementInsideLeg", "http://schema.org/BodyMeasurementInsideLeg" + "BodyMeasurementNeck", "http://schema.org/BodyMeasurementNeck" + "BodyMeasurementTypeEnumeration", "http://schema.org/BodyMeasurementTypeEnumeration" + "BodyMeasurementUnderbust", "http://schema.org/BodyMeasurementUnderbust" + "BodyMeasurementWaist", "http://schema.org/BodyMeasurementWaist" + "BodyMeasurementWeight", "http://schema.org/BodyMeasurementWeight" + "BodyOfWater", "http://schema.org/BodyOfWater" + "Bone", "http://schema.org/Bone" + "Book", "http://schema.org/Book" + "BookFormatType", "http://schema.org/BookFormatType" + "BookSeries", "http://schema.org/BookSeries" + "BookStore", "http://schema.org/BookStore" + "BookmarkAction", "http://schema.org/BookmarkAction" + "Boolean", "http://schema.org/Boolean" + "BorrowAction", "http://schema.org/BorrowAction" + "BowlingAlley", "http://schema.org/BowlingAlley" + "BrainStructure", "http://schema.org/BrainStructure" + "Brand", "http://schema.org/Brand" + "BreadcrumbList", "http://schema.org/BreadcrumbList" + "Brewery", "http://schema.org/Brewery" + "Bridge", "http://schema.org/Bridge" + "BroadcastChannel", "http://schema.org/BroadcastChannel" + "BroadcastEvent", "http://schema.org/BroadcastEvent" + "BroadcastFrequencySpecification", "http://schema.org/BroadcastFrequencySpecification" + "BroadcastRelease", "http://schema.org/BroadcastRelease" + "BroadcastService", "http://schema.org/BroadcastService" + "BrokerageAccount", "http://schema.org/BrokerageAccount" + "BuddhistTemple", "http://schema.org/BuddhistTemple" + "BusOrCoach", "http://schema.org/BusOrCoach" + "BusReservation", "http://schema.org/BusReservation" + "BusStation", "http://schema.org/BusStation" + "BusStop", "http://schema.org/BusStop" + "BusTrip", "http://schema.org/BusTrip" + "BusinessAudience", "http://schema.org/BusinessAudience" + "BusinessEntityType", "http://schema.org/BusinessEntityType" + "BusinessEvent", "http://schema.org/BusinessEvent" + "BusinessFunction", "http://schema.org/BusinessFunction" + "BusinessSupport", "http://schema.org/BusinessSupport" + "BuyAction", "http://schema.org/BuyAction" + "CDCPMDRecord", "http://schema.org/CDCPMDRecord" + "CDFormat", "http://schema.org/CDFormat" + "CT", "http://schema.org/CT" + "CableOrSatelliteService", "http://schema.org/CableOrSatelliteService" + "CafeOrCoffeeShop", "http://schema.org/CafeOrCoffeeShop" + "Campground", "http://schema.org/Campground" + "CampingPitch", "http://schema.org/CampingPitch" + "Canal", "http://schema.org/Canal" + "CancelAction", "http://schema.org/CancelAction" + "Car", "http://schema.org/Car" + "CarUsageType", "http://schema.org/CarUsageType" + "Cardiovascular", "http://schema.org/Cardiovascular" + "CardiovascularExam", "http://schema.org/CardiovascularExam" + "CaseSeries", "http://schema.org/CaseSeries" + "Casino", "http://schema.org/Casino" + "CassetteFormat", "http://schema.org/CassetteFormat" + "CategoryCode", "http://schema.org/CategoryCode" + "CategoryCodeSet", "http://schema.org/CategoryCodeSet" + "CatholicChurch", "http://schema.org/CatholicChurch" + "CausesHealthAspect", "http://schema.org/CausesHealthAspect" + "Cemetery", "http://schema.org/Cemetery" + "Chapter", "http://schema.org/Chapter" + "CharitableIncorporatedOrganization", "http://schema.org/CharitableIncorporatedOrganization" + "CheckAction", "http://schema.org/CheckAction" + "CheckInAction", "http://schema.org/CheckInAction" + "CheckOutAction", "http://schema.org/CheckOutAction" + "CheckoutPage", "http://schema.org/CheckoutPage" + "ChemicalSubstance", "http://schema.org/ChemicalSubstance" + "ChildCare", "http://schema.org/ChildCare" + "ChildrensEvent", "http://schema.org/ChildrensEvent" + "Chiropractic", "http://schema.org/Chiropractic" + "ChooseAction", "http://schema.org/ChooseAction" + "Church", "http://schema.org/Church" + "City", "http://schema.org/City" + "CityHall", "http://schema.org/CityHall" + "CivicStructure", "http://schema.org/CivicStructure" + "Claim", "http://schema.org/Claim" + "ClaimReview", "http://schema.org/ClaimReview" + "Class", "http://schema.org/Class" + "CleaningFee", "http://schema.org/CleaningFee" + "Clinician", "http://schema.org/Clinician" + "Clip", "http://schema.org/Clip" + "ClothingStore", "http://schema.org/ClothingStore" + "CoOp", "http://schema.org/CoOp" + "Code", "http://schema.org/Code" + "CohortStudy", "http://schema.org/CohortStudy" + "Collection", "http://schema.org/Collection" + "CollectionPage", "http://schema.org/CollectionPage" + "CollegeOrUniversity", "http://schema.org/CollegeOrUniversity" + "ComedyClub", "http://schema.org/ComedyClub" + "ComedyEvent", "http://schema.org/ComedyEvent" + "ComicCoverArt", "http://schema.org/ComicCoverArt" + "ComicIssue", "http://schema.org/ComicIssue" + "ComicSeries", "http://schema.org/ComicSeries" + "ComicStory", "http://schema.org/ComicStory" + "Comment", "http://schema.org/Comment" + "CommentAction", "http://schema.org/CommentAction" + "CommentPermission", "http://schema.org/CommentPermission" + "CommunicateAction", "http://schema.org/CommunicateAction" + "CommunityHealth", "http://schema.org/CommunityHealth" + "CompilationAlbum", "http://schema.org/CompilationAlbum" + "CompleteDataFeed", "http://schema.org/CompleteDataFeed" + "Completed", "http://schema.org/Completed" + "CompletedActionStatus", "http://schema.org/CompletedActionStatus" + "CompoundPriceSpecification", "http://schema.org/CompoundPriceSpecification" + "ComputerLanguage", "http://schema.org/ComputerLanguage" + "ComputerStore", "http://schema.org/ComputerStore" + "ConfirmAction", "http://schema.org/ConfirmAction" + "Consortium", "http://schema.org/Consortium" + "ConstraintNode", "http://schema.org/ConstraintNode" + "ConsumeAction", "http://schema.org/ConsumeAction" + "ContactPage", "http://schema.org/ContactPage" + "ContactPoint", "http://schema.org/ContactPoint" + "ContactPointOption", "http://schema.org/ContactPointOption" + "ContagiousnessHealthAspect", "http://schema.org/ContagiousnessHealthAspect" + "Continent", "http://schema.org/Continent" + "ControlAction", "http://schema.org/ControlAction" + "ConvenienceStore", "http://schema.org/ConvenienceStore" + "Conversation", "http://schema.org/Conversation" + "CookAction", "http://schema.org/CookAction" + "Corporation", "http://schema.org/Corporation" + "CorrectionComment", "http://schema.org/CorrectionComment" + "Country", "http://schema.org/Country" + "Course", "http://schema.org/Course" + "CourseInstance", "http://schema.org/CourseInstance" + "Courthouse", "http://schema.org/Courthouse" + "CoverArt", "http://schema.org/CoverArt" + "CovidTestingFacility", "http://schema.org/CovidTestingFacility" + "CreateAction", "http://schema.org/CreateAction" + "CreativeWork", "http://schema.org/CreativeWork" + "CreativeWorkSeason", "http://schema.org/CreativeWorkSeason" + "CreativeWorkSeries", "http://schema.org/CreativeWorkSeries" + "CreditCard", "http://schema.org/CreditCard" + "Crematorium", "http://schema.org/Crematorium" + "CriticReview", "http://schema.org/CriticReview" + "CrossSectional", "http://schema.org/CrossSectional" + "CssSelectorType", "http://schema.org/CssSelectorType" + "CurrencyConversionService", "http://schema.org/CurrencyConversionService" + "DDxElement", "http://schema.org/DDxElement" + "DJMixAlbum", "http://schema.org/DJMixAlbum" + "DVDFormat", "http://schema.org/DVDFormat" + "DamagedCondition", "http://schema.org/DamagedCondition" + "DanceEvent", "http://schema.org/DanceEvent" + "DanceGroup", "http://schema.org/DanceGroup" + "DangerousGoodConsideration", "http://schema.org/DangerousGoodConsideration" + "DataCatalog", "http://schema.org/DataCatalog" + "DataDownload", "http://schema.org/DataDownload" + "DataFeed", "http://schema.org/DataFeed" + "DataFeedItem", "http://schema.org/DataFeedItem" + "DataType", "http://schema.org/DataType" + "Dataset", "http://schema.org/Dataset" + "Date", "http://schema.org/Date" + "DateTime", "http://schema.org/DateTime" + "DatedMoneySpecification", "http://schema.org/DatedMoneySpecification" + "DayOfWeek", "http://schema.org/DayOfWeek" + "DaySpa", "http://schema.org/DaySpa" + "DeactivateAction", "http://schema.org/DeactivateAction" + "DecontextualizedContent", "http://schema.org/DecontextualizedContent" + "DefenceEstablishment", "http://schema.org/DefenceEstablishment" + "DefinedRegion", "http://schema.org/DefinedRegion" + "DefinedTerm", "http://schema.org/DefinedTerm" + "DefinedTermSet", "http://schema.org/DefinedTermSet" + "DefinitiveLegalValue", "http://schema.org/DefinitiveLegalValue" + "DeleteAction", "http://schema.org/DeleteAction" + "DeliveryChargeSpecification", "http://schema.org/DeliveryChargeSpecification" + "DeliveryEvent", "http://schema.org/DeliveryEvent" + "DeliveryMethod", "http://schema.org/DeliveryMethod" + "DeliveryTimeSettings", "http://schema.org/DeliveryTimeSettings" + "Demand", "http://schema.org/Demand" + "DemoAlbum", "http://schema.org/DemoAlbum" + "DemoGameAvailability", "http://schema.org/DemoGameAvailability" + "Dentist", "http://schema.org/Dentist" + "Dentistry", "http://schema.org/Dentistry" + "DepartAction", "http://schema.org/DepartAction" + "DepartmentStore", "http://schema.org/DepartmentStore" + "DepositAccount", "http://schema.org/DepositAccount" + "Dermatologic", "http://schema.org/Dermatologic" + "Dermatology", "http://schema.org/Dermatology" + "DesktopWebPlatform", "http://schema.org/DesktopWebPlatform" + "DiabeticDiet", "http://schema.org/DiabeticDiet" + "Diagnostic", "http://schema.org/Diagnostic" + "DiagnosticLab", "http://schema.org/DiagnosticLab" + "DiagnosticProcedure", "http://schema.org/DiagnosticProcedure" + "Diet", "http://schema.org/Diet" + "DietNutrition", "http://schema.org/DietNutrition" + "DietarySupplement", "http://schema.org/DietarySupplement" + "DigitalAudioTapeFormat", "http://schema.org/DigitalAudioTapeFormat" + "DigitalDocument", "http://schema.org/DigitalDocument" + "DigitalDocumentPermission", "http://schema.org/DigitalDocumentPermission" + "DigitalDocumentPermissionType", "http://schema.org/DigitalDocumentPermissionType" + "DigitalFormat", "http://schema.org/DigitalFormat" + "DigitalPlatformEnumeration", "http://schema.org/DigitalPlatformEnumeration" + "DisabilitySupport", "http://schema.org/DisabilitySupport" + "DisagreeAction", "http://schema.org/DisagreeAction" + "Discontinued", "http://schema.org/Discontinued" + "DiscoverAction", "http://schema.org/DiscoverAction" + "DiscussionForumPosting", "http://schema.org/DiscussionForumPosting" + "DislikeAction", "http://schema.org/DislikeAction" + "Distance", "http://schema.org/Distance" + "DistanceFee", "http://schema.org/DistanceFee" + "Distillery", "http://schema.org/Distillery" + "DonateAction", "http://schema.org/DonateAction" + "DoseSchedule", "http://schema.org/DoseSchedule" + "DoubleBlindedTrial", "http://schema.org/DoubleBlindedTrial" + "DownloadAction", "http://schema.org/DownloadAction" + "Downpayment", "http://schema.org/Downpayment" + "DrawAction", "http://schema.org/DrawAction" + "Drawing", "http://schema.org/Drawing" + "DrinkAction", "http://schema.org/DrinkAction" + "DriveWheelConfigurationValue", "http://schema.org/DriveWheelConfigurationValue" + "DrivingSchoolVehicleUsage", "http://schema.org/DrivingSchoolVehicleUsage" + "Drug", "http://schema.org/Drug" + "DrugClass", "http://schema.org/DrugClass" + "DrugCost", "http://schema.org/DrugCost" + "DrugCostCategory", "http://schema.org/DrugCostCategory" + "DrugLegalStatus", "http://schema.org/DrugLegalStatus" + "DrugPregnancyCategory", "http://schema.org/DrugPregnancyCategory" + "DrugPrescriptionStatus", "http://schema.org/DrugPrescriptionStatus" + "DrugStrength", "http://schema.org/DrugStrength" + "DryCleaningOrLaundry", "http://schema.org/DryCleaningOrLaundry" + "Duration", "http://schema.org/Duration" + "EBook", "http://schema.org/EBook" + "EPRelease", "http://schema.org/EPRelease" + "EUEnergyEfficiencyCategoryA", "http://schema.org/EUEnergyEfficiencyCategoryA" + "EUEnergyEfficiencyCategoryA1Plus", "http://schema.org/EUEnergyEfficiencyCategoryA1Plus" + "EUEnergyEfficiencyCategoryA2Plus", "http://schema.org/EUEnergyEfficiencyCategoryA2Plus" + "EUEnergyEfficiencyCategoryA3Plus", "http://schema.org/EUEnergyEfficiencyCategoryA3Plus" + "EUEnergyEfficiencyCategoryB", "http://schema.org/EUEnergyEfficiencyCategoryB" + "EUEnergyEfficiencyCategoryC", "http://schema.org/EUEnergyEfficiencyCategoryC" + "EUEnergyEfficiencyCategoryD", "http://schema.org/EUEnergyEfficiencyCategoryD" + "EUEnergyEfficiencyCategoryE", "http://schema.org/EUEnergyEfficiencyCategoryE" + "EUEnergyEfficiencyCategoryF", "http://schema.org/EUEnergyEfficiencyCategoryF" + "EUEnergyEfficiencyCategoryG", "http://schema.org/EUEnergyEfficiencyCategoryG" + "EUEnergyEfficiencyEnumeration", "http://schema.org/EUEnergyEfficiencyEnumeration" + "Ear", "http://schema.org/Ear" + "EatAction", "http://schema.org/EatAction" + "EditedOrCroppedContent", "http://schema.org/EditedOrCroppedContent" + "EducationEvent", "http://schema.org/EducationEvent" + "EducationalAudience", "http://schema.org/EducationalAudience" + "EducationalOccupationalCredential", "http://schema.org/EducationalOccupationalCredential" + "EducationalOccupationalProgram", "http://schema.org/EducationalOccupationalProgram" + "EducationalOrganization", "http://schema.org/EducationalOrganization" + "EffectivenessHealthAspect", "http://schema.org/EffectivenessHealthAspect" + "Electrician", "http://schema.org/Electrician" + "ElectronicsStore", "http://schema.org/ElectronicsStore" + "ElementarySchool", "http://schema.org/ElementarySchool" + "EmailMessage", "http://schema.org/EmailMessage" + "Embassy", "http://schema.org/Embassy" + "Emergency", "http://schema.org/Emergency" + "EmergencyService", "http://schema.org/EmergencyService" + "EmployeeRole", "http://schema.org/EmployeeRole" + "EmployerAggregateRating", "http://schema.org/EmployerAggregateRating" + "EmployerReview", "http://schema.org/EmployerReview" + "EmploymentAgency", "http://schema.org/EmploymentAgency" + "Endocrine", "http://schema.org/Endocrine" + "EndorseAction", "http://schema.org/EndorseAction" + "EndorsementRating", "http://schema.org/EndorsementRating" + "Energy", "http://schema.org/Energy" + "EnergyConsumptionDetails", "http://schema.org/EnergyConsumptionDetails" + "EnergyEfficiencyEnumeration", "http://schema.org/EnergyEfficiencyEnumeration" + "EnergyStarCertified", "http://schema.org/EnergyStarCertified" + "EnergyStarEnergyEfficiencyEnumeration", "http://schema.org/EnergyStarEnergyEfficiencyEnumeration" + "EngineSpecification", "http://schema.org/EngineSpecification" + "EnrollingByInvitation", "http://schema.org/EnrollingByInvitation" + "EntertainmentBusiness", "http://schema.org/EntertainmentBusiness" + "EntryPoint", "http://schema.org/EntryPoint" + "Enumeration", "http://schema.org/Enumeration" + "Episode", "http://schema.org/Episode" + "Event", "http://schema.org/Event" + "EventAttendanceModeEnumeration", "http://schema.org/EventAttendanceModeEnumeration" + "EventCancelled", "http://schema.org/EventCancelled" + "EventMovedOnline", "http://schema.org/EventMovedOnline" + "EventPostponed", "http://schema.org/EventPostponed" + "EventRescheduled", "http://schema.org/EventRescheduled" + "EventReservation", "http://schema.org/EventReservation" + "EventScheduled", "http://schema.org/EventScheduled" + "EventSeries", "http://schema.org/EventSeries" + "EventStatusType", "http://schema.org/EventStatusType" + "EventVenue", "http://schema.org/EventVenue" + "EvidenceLevelA", "http://schema.org/EvidenceLevelA" + "EvidenceLevelB", "http://schema.org/EvidenceLevelB" + "EvidenceLevelC", "http://schema.org/EvidenceLevelC" + "ExampleMeasurementMethodEnum", "http://schema.org/ExampleMeasurementMethodEnum" + "ExchangeRateSpecification", "http://schema.org/ExchangeRateSpecification" + "ExchangeRefund", "http://schema.org/ExchangeRefund" + "ExerciseAction", "http://schema.org/ExerciseAction" + "ExerciseGym", "http://schema.org/ExerciseGym" + "ExercisePlan", "http://schema.org/ExercisePlan" + "ExhibitionEvent", "http://schema.org/ExhibitionEvent" + "Eye", "http://schema.org/Eye" + "FAQPage", "http://schema.org/FAQPage" + "FDAcategoryA", "http://schema.org/FDAcategoryA" + "FDAcategoryB", "http://schema.org/FDAcategoryB" + "FDAcategoryC", "http://schema.org/FDAcategoryC" + "FDAcategoryD", "http://schema.org/FDAcategoryD" + "FDAcategoryX", "http://schema.org/FDAcategoryX" + "FDAnotEvaluated", "http://schema.org/FDAnotEvaluated" + "FMRadioChannel", "http://schema.org/FMRadioChannel" + "FailedActionStatus", "http://schema.org/FailedActionStatus" + "False", "http://schema.org/False" + "FastFoodRestaurant", "http://schema.org/FastFoodRestaurant" + "Female", "http://schema.org/Female" + "Festival", "http://schema.org/Festival" + "FilmAction", "http://schema.org/FilmAction" + "FinancialProduct", "http://schema.org/FinancialProduct" + "FinancialService", "http://schema.org/FinancialService" + "FindAction", "http://schema.org/FindAction" + "FireStation", "http://schema.org/FireStation" + "Flexibility", "http://schema.org/Flexibility" + "Flight", "http://schema.org/Flight" + "FlightReservation", "http://schema.org/FlightReservation" + "Float", "http://schema.org/Float" + "FloorPlan", "http://schema.org/FloorPlan" + "Florist", "http://schema.org/Florist" + "FollowAction", "http://schema.org/FollowAction" + "FoodEstablishment", "http://schema.org/FoodEstablishment" + "FoodEstablishmentReservation", "http://schema.org/FoodEstablishmentReservation" + "FoodEvent", "http://schema.org/FoodEvent" + "FoodService", "http://schema.org/FoodService" + "FourWheelDriveConfiguration", "http://schema.org/FourWheelDriveConfiguration" + "FreeReturn", "http://schema.org/FreeReturn" + "Friday", "http://schema.org/Friday" + "FrontWheelDriveConfiguration", "http://schema.org/FrontWheelDriveConfiguration" + "FullGameAvailability", "http://schema.org/FullGameAvailability" + "FullRefund", "http://schema.org/FullRefund" + "FundingAgency", "http://schema.org/FundingAgency" + "FundingScheme", "http://schema.org/FundingScheme" + "Fungus", "http://schema.org/Fungus" + "FurnitureStore", "http://schema.org/FurnitureStore" + "Game", "http://schema.org/Game" + "GameAvailabilityEnumeration", "http://schema.org/GameAvailabilityEnumeration" + "GamePlayMode", "http://schema.org/GamePlayMode" + "GameServer", "http://schema.org/GameServer" + "GameServerStatus", "http://schema.org/GameServerStatus" + "GardenStore", "http://schema.org/GardenStore" + "GasStation", "http://schema.org/GasStation" + "Gastroenterologic", "http://schema.org/Gastroenterologic" + "GatedResidenceCommunity", "http://schema.org/GatedResidenceCommunity" + "GenderType", "http://schema.org/GenderType" + "Gene", "http://schema.org/Gene" + "GeneralContractor", "http://schema.org/GeneralContractor" + "GenericWebPlatform", "http://schema.org/GenericWebPlatform" + "Genetic", "http://schema.org/Genetic" + "Genitourinary", "http://schema.org/Genitourinary" + "GeoCircle", "http://schema.org/GeoCircle" + "GeoCoordinates", "http://schema.org/GeoCoordinates" + "GeoShape", "http://schema.org/GeoShape" + "GeospatialGeometry", "http://schema.org/GeospatialGeometry" + "Geriatric", "http://schema.org/Geriatric" + "GettingAccessHealthAspect", "http://schema.org/GettingAccessHealthAspect" + "GiveAction", "http://schema.org/GiveAction" + "GlutenFreeDiet", "http://schema.org/GlutenFreeDiet" + "GolfCourse", "http://schema.org/GolfCourse" + "GovernmentBenefitsType", "http://schema.org/GovernmentBenefitsType" + "GovernmentBuilding", "http://schema.org/GovernmentBuilding" + "GovernmentOffice", "http://schema.org/GovernmentOffice" + "GovernmentOrganization", "http://schema.org/GovernmentOrganization" + "GovernmentPermit", "http://schema.org/GovernmentPermit" + "GovernmentService", "http://schema.org/GovernmentService" + "Grant", "http://schema.org/Grant" + "GraphicNovel", "http://schema.org/GraphicNovel" + "GroceryStore", "http://schema.org/GroceryStore" + "GroupBoardingPolicy", "http://schema.org/GroupBoardingPolicy" + "Guide", "http://schema.org/Guide" + "Gynecologic", "http://schema.org/Gynecologic" + "HTML", "rdf:HTML" + "HVACBusiness", "http://schema.org/HVACBusiness" + "Hackathon", "http://schema.org/Hackathon" + "HairSalon", "http://schema.org/HairSalon" + "HalalDiet", "http://schema.org/HalalDiet" + "Hardcover", "http://schema.org/Hardcover" + "HardwareStore", "http://schema.org/HardwareStore" + "Head", "http://schema.org/Head" + "HealthAndBeautyBusiness", "http://schema.org/HealthAndBeautyBusiness" + "HealthAspectEnumeration", "http://schema.org/HealthAspectEnumeration" + "HealthCare", "http://schema.org/HealthCare" + "HealthClub", "http://schema.org/HealthClub" + "HealthInsurancePlan", "http://schema.org/HealthInsurancePlan" + "HealthPlanCostSharingSpecification", "http://schema.org/HealthPlanCostSharingSpecification" + "HealthPlanFormulary", "http://schema.org/HealthPlanFormulary" + "HealthPlanNetwork", "http://schema.org/HealthPlanNetwork" + "HealthTopicContent", "http://schema.org/HealthTopicContent" + "HealthcareConsideration", "http://schema.org/HealthcareConsideration" + "HearingImpairedSupported", "http://schema.org/HearingImpairedSupported" + "Hematologic", "http://schema.org/Hematologic" + "HighSchool", "http://schema.org/HighSchool" + "HinduDiet", "http://schema.org/HinduDiet" + "HinduTemple", "http://schema.org/HinduTemple" + "HobbyShop", "http://schema.org/HobbyShop" + "HomeAndConstructionBusiness", "http://schema.org/HomeAndConstructionBusiness" + "HomeGoodsStore", "http://schema.org/HomeGoodsStore" + "Homeopathic", "http://schema.org/Homeopathic" + "Hospital", "http://schema.org/Hospital" + "Hostel", "http://schema.org/Hostel" + "Hotel", "http://schema.org/Hotel" + "HotelRoom", "http://schema.org/HotelRoom" + "House", "http://schema.org/House" + "HousePainter", "http://schema.org/HousePainter" + "HowItWorksHealthAspect", "http://schema.org/HowItWorksHealthAspect" + "HowOrWhereHealthAspect", "http://schema.org/HowOrWhereHealthAspect" + "HowTo", "http://schema.org/HowTo" + "HowToDirection", "http://schema.org/HowToDirection" + "HowToItem", "http://schema.org/HowToItem" + "HowToSection", "http://schema.org/HowToSection" + "HowToStep", "http://schema.org/HowToStep" + "HowToSupply", "http://schema.org/HowToSupply" + "HowToTip", "http://schema.org/HowToTip" + "HowToTool", "http://schema.org/HowToTool" + "HyperToc", "http://schema.org/HyperToc" + "HyperTocEntry", "http://schema.org/HyperTocEntry" + "IOSPlatform", "http://schema.org/IOSPlatform" + "IceCreamShop", "http://schema.org/IceCreamShop" + "IgnoreAction", "http://schema.org/IgnoreAction" + "ImageGallery", "http://schema.org/ImageGallery" + "ImageObject", "http://schema.org/ImageObject" + "ImageObjectSnapshot", "http://schema.org/ImageObjectSnapshot" + "ImagingTest", "http://schema.org/ImagingTest" + "InForce", "http://schema.org/InForce" + "InStock", "http://schema.org/InStock" + "InStoreOnly", "http://schema.org/InStoreOnly" + "IndividualProduct", "http://schema.org/IndividualProduct" + "Infectious", "http://schema.org/Infectious" + "InfectiousAgentClass", "http://schema.org/InfectiousAgentClass" + "InfectiousDisease", "http://schema.org/InfectiousDisease" + "InformAction", "http://schema.org/InformAction" + "IngredientsHealthAspect", "http://schema.org/IngredientsHealthAspect" + "InsertAction", "http://schema.org/InsertAction" + "InstallAction", "http://schema.org/InstallAction" + "Installment", "http://schema.org/Installment" + "InsuranceAgency", "http://schema.org/InsuranceAgency" + "Intangible", "http://schema.org/Intangible" + "Integer", "http://schema.org/Integer" + "InteractAction", "http://schema.org/InteractAction" + "InteractionCounter", "http://schema.org/InteractionCounter" + "InternationalTrial", "http://schema.org/InternationalTrial" + "InternetCafe", "http://schema.org/InternetCafe" + "InvestmentFund", "http://schema.org/InvestmentFund" + "InvestmentOrDeposit", "http://schema.org/InvestmentOrDeposit" + "InviteAction", "http://schema.org/InviteAction" + "Invoice", "http://schema.org/Invoice" + "InvoicePrice", "http://schema.org/InvoicePrice" + "ItemAvailability", "http://schema.org/ItemAvailability" + "ItemList", "http://schema.org/ItemList" + "ItemListOrderAscending", "http://schema.org/ItemListOrderAscending" + "ItemListOrderDescending", "http://schema.org/ItemListOrderDescending" + "ItemListOrderType", "http://schema.org/ItemListOrderType" + "ItemListUnordered", "http://schema.org/ItemListUnordered" + "ItemPage", "http://schema.org/ItemPage" + "JewelryStore", "http://schema.org/JewelryStore" + "JobPosting", "http://schema.org/JobPosting" + "JoinAction", "http://schema.org/JoinAction" + "Joint", "http://schema.org/Joint" + "KosherDiet", "http://schema.org/KosherDiet" + "LaboratoryScience", "http://schema.org/LaboratoryScience" + "LakeBodyOfWater", "http://schema.org/LakeBodyOfWater" + "Landform", "http://schema.org/Landform" + "LandmarksOrHistoricalBuildings", "http://schema.org/LandmarksOrHistoricalBuildings" + "Language", "http://schema.org/Language" + "LaserDiscFormat", "http://schema.org/LaserDiscFormat" + "LearningResource", "http://schema.org/LearningResource" + "LeaveAction", "http://schema.org/LeaveAction" + "LeftHandDriving", "http://schema.org/LeftHandDriving" + "LegalForceStatus", "http://schema.org/LegalForceStatus" + "LegalService", "http://schema.org/LegalService" + "LegalValueLevel", "http://schema.org/LegalValueLevel" + "Legislation", "http://schema.org/Legislation" + "LegislationObject", "http://schema.org/LegislationObject" + "LegislativeBuilding", "http://schema.org/LegislativeBuilding" + "LeisureTimeActivity", "http://schema.org/LeisureTimeActivity" + "LendAction", "http://schema.org/LendAction" + "Library", "http://schema.org/Library" + "LibrarySystem", "http://schema.org/LibrarySystem" + "LifestyleModification", "http://schema.org/LifestyleModification" + "Ligament", "http://schema.org/Ligament" + "LikeAction", "http://schema.org/LikeAction" + "LimitedAvailability", "http://schema.org/LimitedAvailability" + "LimitedByGuaranteeCharity", "http://schema.org/LimitedByGuaranteeCharity" + "LinkRole", "http://schema.org/LinkRole" + "LiquorStore", "http://schema.org/LiquorStore" + "ListItem", "http://schema.org/ListItem" + "ListPrice", "http://schema.org/ListPrice" + "ListenAction", "http://schema.org/ListenAction" + "LiteraryEvent", "http://schema.org/LiteraryEvent" + "LiveAlbum", "http://schema.org/LiveAlbum" + "LiveBlogPosting", "http://schema.org/LiveBlogPosting" + "LivingWithHealthAspect", "http://schema.org/LivingWithHealthAspect" + "LoanOrCredit", "http://schema.org/LoanOrCredit" + "LocalBusiness", "http://schema.org/LocalBusiness" + "LocationFeatureSpecification", "http://schema.org/LocationFeatureSpecification" + "LockerDelivery", "http://schema.org/LockerDelivery" + "Locksmith", "http://schema.org/Locksmith" + "LodgingBusiness", "http://schema.org/LodgingBusiness" + "LodgingReservation", "http://schema.org/LodgingReservation" + "Longitudinal", "http://schema.org/Longitudinal" + "LoseAction", "http://schema.org/LoseAction" + "LowCalorieDiet", "http://schema.org/LowCalorieDiet" + "LowFatDiet", "http://schema.org/LowFatDiet" + "LowLactoseDiet", "http://schema.org/LowLactoseDiet" + "LowSaltDiet", "http://schema.org/LowSaltDiet" + "Lung", "http://schema.org/Lung" + "LymphaticVessel", "http://schema.org/LymphaticVessel" + "MRI", "http://schema.org/MRI" + "MSRP", "http://schema.org/MSRP" + "Male", "http://schema.org/Male" + "Manuscript", "http://schema.org/Manuscript" + "Map", "http://schema.org/Map" + "MapCategoryType", "http://schema.org/MapCategoryType" + "MarryAction", "http://schema.org/MarryAction" + "Mass", "http://schema.org/Mass" + "MathSolver", "http://schema.org/MathSolver" + "MaximumDoseSchedule", "http://schema.org/MaximumDoseSchedule" + "MayTreatHealthAspect", "http://schema.org/MayTreatHealthAspect" + "MeasurementMethodEnum", "http://schema.org/MeasurementMethodEnum" + "MeasurementTypeEnumeration", "http://schema.org/MeasurementTypeEnumeration" + "MediaGallery", "http://schema.org/MediaGallery" + "MediaManipulationRatingEnumeration", "http://schema.org/MediaManipulationRatingEnumeration" + "MediaObject", "http://schema.org/MediaObject" + "MediaReview", "http://schema.org/MediaReview" + "MediaReviewItem", "http://schema.org/MediaReviewItem" + "MediaSubscription", "http://schema.org/MediaSubscription" + "MedicalAudience", "http://schema.org/MedicalAudience" + "MedicalAudienceType", "http://schema.org/MedicalAudienceType" + "MedicalBusiness", "http://schema.org/MedicalBusiness" + "MedicalCause", "http://schema.org/MedicalCause" + "MedicalClinic", "http://schema.org/MedicalClinic" + "MedicalCode", "http://schema.org/MedicalCode" + "MedicalCondition", "http://schema.org/MedicalCondition" + "MedicalConditionStage", "http://schema.org/MedicalConditionStage" + "MedicalContraindication", "http://schema.org/MedicalContraindication" + "MedicalDevice", "http://schema.org/MedicalDevice" + "MedicalDevicePurpose", "http://schema.org/MedicalDevicePurpose" + "MedicalEntity", "http://schema.org/MedicalEntity" + "MedicalEnumeration", "http://schema.org/MedicalEnumeration" + "MedicalEvidenceLevel", "http://schema.org/MedicalEvidenceLevel" + "MedicalGuideline", "http://schema.org/MedicalGuideline" + "MedicalGuidelineContraindication", "http://schema.org/MedicalGuidelineContraindication" + "MedicalGuidelineRecommendation", "http://schema.org/MedicalGuidelineRecommendation" + "MedicalImagingTechnique", "http://schema.org/MedicalImagingTechnique" + "MedicalIndication", "http://schema.org/MedicalIndication" + "MedicalIntangible", "http://schema.org/MedicalIntangible" + "MedicalObservationalStudy", "http://schema.org/MedicalObservationalStudy" + "MedicalObservationalStudyDesign", "http://schema.org/MedicalObservationalStudyDesign" + "MedicalOrganization", "http://schema.org/MedicalOrganization" + "MedicalProcedure", "http://schema.org/MedicalProcedure" + "MedicalProcedureType", "http://schema.org/MedicalProcedureType" + "MedicalResearcher", "http://schema.org/MedicalResearcher" + "MedicalRiskCalculator", "http://schema.org/MedicalRiskCalculator" + "MedicalRiskEstimator", "http://schema.org/MedicalRiskEstimator" + "MedicalRiskFactor", "http://schema.org/MedicalRiskFactor" + "MedicalRiskScore", "http://schema.org/MedicalRiskScore" + "MedicalScholarlyArticle", "http://schema.org/MedicalScholarlyArticle" + "MedicalSign", "http://schema.org/MedicalSign" + "MedicalSignOrSymptom", "http://schema.org/MedicalSignOrSymptom" + "MedicalSpecialty", "http://schema.org/MedicalSpecialty" + "MedicalStudy", "http://schema.org/MedicalStudy" + "MedicalStudyStatus", "http://schema.org/MedicalStudyStatus" + "MedicalSymptom", "http://schema.org/MedicalSymptom" + "MedicalTest", "http://schema.org/MedicalTest" + "MedicalTestPanel", "http://schema.org/MedicalTestPanel" + "MedicalTherapy", "http://schema.org/MedicalTherapy" + "MedicalTrial", "http://schema.org/MedicalTrial" + "MedicalTrialDesign", "http://schema.org/MedicalTrialDesign" + "MedicalWebPage", "http://schema.org/MedicalWebPage" + "MedicineSystem", "http://schema.org/MedicineSystem" + "MeetingRoom", "http://schema.org/MeetingRoom" + "MensClothingStore", "http://schema.org/MensClothingStore" + "Menu", "http://schema.org/Menu" + "MenuItem", "http://schema.org/MenuItem" + "MenuSection", "http://schema.org/MenuSection" + "MerchantReturnEnumeration", "http://schema.org/MerchantReturnEnumeration" + "MerchantReturnFiniteReturnWindow", "http://schema.org/MerchantReturnFiniteReturnWindow" + "MerchantReturnNotPermitted", "http://schema.org/MerchantReturnNotPermitted" + "MerchantReturnPolicy", "http://schema.org/MerchantReturnPolicy" + "MerchantReturnPolicySeasonalOverride", "http://schema.org/MerchantReturnPolicySeasonalOverride" + "MerchantReturnUnlimitedWindow", "http://schema.org/MerchantReturnUnlimitedWindow" + "MerchantReturnUnspecified", "http://schema.org/MerchantReturnUnspecified" + "Message", "http://schema.org/Message" + "MiddleSchool", "http://schema.org/MiddleSchool" + "Midwifery", "http://schema.org/Midwifery" + "MinimumAdvertisedPrice", "http://schema.org/MinimumAdvertisedPrice" + "MisconceptionsHealthAspect", "http://schema.org/MisconceptionsHealthAspect" + "MixedEventAttendanceMode", "http://schema.org/MixedEventAttendanceMode" + "MixtapeAlbum", "http://schema.org/MixtapeAlbum" + "MobileApplication", "http://schema.org/MobileApplication" + "MobilePhoneStore", "http://schema.org/MobilePhoneStore" + "MobileWebPlatform", "http://schema.org/MobileWebPlatform" + "MolecularEntity", "http://schema.org/MolecularEntity" + "Monday", "http://schema.org/Monday" + "MonetaryAmount", "http://schema.org/MonetaryAmount" + "MonetaryAmountDistribution", "http://schema.org/MonetaryAmountDistribution" + "MonetaryGrant", "http://schema.org/MonetaryGrant" + "MoneyTransfer", "http://schema.org/MoneyTransfer" + "MortgageLoan", "http://schema.org/MortgageLoan" + "Mosque", "http://schema.org/Mosque" + "Motel", "http://schema.org/Motel" + "Motorcycle", "http://schema.org/Motorcycle" + "MotorcycleDealer", "http://schema.org/MotorcycleDealer" + "MotorcycleRepair", "http://schema.org/MotorcycleRepair" + "MotorizedBicycle", "http://schema.org/MotorizedBicycle" + "Mountain", "http://schema.org/Mountain" + "MoveAction", "http://schema.org/MoveAction" + "Movie", "http://schema.org/Movie" + "MovieClip", "http://schema.org/MovieClip" + "MovieRentalStore", "http://schema.org/MovieRentalStore" + "MovieSeries", "http://schema.org/MovieSeries" + "MovieTheater", "http://schema.org/MovieTheater" + "MovingCompany", "http://schema.org/MovingCompany" + "MultiCenterTrial", "http://schema.org/MultiCenterTrial" + "MultiPlayer", "http://schema.org/MultiPlayer" + "MulticellularParasite", "http://schema.org/MulticellularParasite" + "Muscle", "http://schema.org/Muscle" + "Musculoskeletal", "http://schema.org/Musculoskeletal" + "MusculoskeletalExam", "http://schema.org/MusculoskeletalExam" + "Museum", "http://schema.org/Museum" + "MusicAlbum", "http://schema.org/MusicAlbum" + "MusicAlbumProductionType", "http://schema.org/MusicAlbumProductionType" + "MusicAlbumReleaseType", "http://schema.org/MusicAlbumReleaseType" + "MusicComposition", "http://schema.org/MusicComposition" + "MusicEvent", "http://schema.org/MusicEvent" + "MusicGroup", "http://schema.org/MusicGroup" + "MusicPlaylist", "http://schema.org/MusicPlaylist" + "MusicRecording", "http://schema.org/MusicRecording" + "MusicRelease", "http://schema.org/MusicRelease" + "MusicReleaseFormatType", "http://schema.org/MusicReleaseFormatType" + "MusicStore", "http://schema.org/MusicStore" + "MusicVenue", "http://schema.org/MusicVenue" + "MusicVideoObject", "http://schema.org/MusicVideoObject" + "NGO", "http://schema.org/NGO" + "NLNonprofitType", "http://schema.org/NLNonprofitType" + "NailSalon", "http://schema.org/NailSalon" + "NarcoticConsideration", "http://schema.org/NarcoticConsideration" + "Neck", "http://schema.org/Neck" + "Nerve", "http://schema.org/Nerve" + "Neuro", "http://schema.org/Neuro" + "Neurologic", "http://schema.org/Neurologic" + "NewCondition", "http://schema.org/NewCondition" + "NewsArticle", "http://schema.org/NewsArticle" + "NewsMediaOrganization", "http://schema.org/NewsMediaOrganization" + "Newspaper", "http://schema.org/Newspaper" + "NightClub", "http://schema.org/NightClub" + "NoninvasiveProcedure", "http://schema.org/NoninvasiveProcedure" + "Nonprofit501a", "http://schema.org/Nonprofit501a" + "Nonprofit501c1", "http://schema.org/Nonprofit501c1" + "Nonprofit501c10", "http://schema.org/Nonprofit501c10" + "Nonprofit501c11", "http://schema.org/Nonprofit501c11" + "Nonprofit501c12", "http://schema.org/Nonprofit501c12" + "Nonprofit501c13", "http://schema.org/Nonprofit501c13" + "Nonprofit501c14", "http://schema.org/Nonprofit501c14" + "Nonprofit501c15", "http://schema.org/Nonprofit501c15" + "Nonprofit501c16", "http://schema.org/Nonprofit501c16" + "Nonprofit501c17", "http://schema.org/Nonprofit501c17" + "Nonprofit501c18", "http://schema.org/Nonprofit501c18" + "Nonprofit501c19", "http://schema.org/Nonprofit501c19" + "Nonprofit501c2", "http://schema.org/Nonprofit501c2" + "Nonprofit501c20", "http://schema.org/Nonprofit501c20" + "Nonprofit501c21", "http://schema.org/Nonprofit501c21" + "Nonprofit501c22", "http://schema.org/Nonprofit501c22" + "Nonprofit501c23", "http://schema.org/Nonprofit501c23" + "Nonprofit501c24", "http://schema.org/Nonprofit501c24" + "Nonprofit501c25", "http://schema.org/Nonprofit501c25" + "Nonprofit501c26", "http://schema.org/Nonprofit501c26" + "Nonprofit501c27", "http://schema.org/Nonprofit501c27" + "Nonprofit501c28", "http://schema.org/Nonprofit501c28" + "Nonprofit501c3", "http://schema.org/Nonprofit501c3" + "Nonprofit501c4", "http://schema.org/Nonprofit501c4" + "Nonprofit501c5", "http://schema.org/Nonprofit501c5" + "Nonprofit501c6", "http://schema.org/Nonprofit501c6" + "Nonprofit501c7", "http://schema.org/Nonprofit501c7" + "Nonprofit501c8", "http://schema.org/Nonprofit501c8" + "Nonprofit501c9", "http://schema.org/Nonprofit501c9" + "Nonprofit501d", "http://schema.org/Nonprofit501d" + "Nonprofit501e", "http://schema.org/Nonprofit501e" + "Nonprofit501f", "http://schema.org/Nonprofit501f" + "Nonprofit501k", "http://schema.org/Nonprofit501k" + "Nonprofit501n", "http://schema.org/Nonprofit501n" + "Nonprofit501q", "http://schema.org/Nonprofit501q" + "Nonprofit527", "http://schema.org/Nonprofit527" + "NonprofitANBI", "http://schema.org/NonprofitANBI" + "NonprofitSBBI", "http://schema.org/NonprofitSBBI" + "NonprofitType", "http://schema.org/NonprofitType" + "Nose", "http://schema.org/Nose" + "NotInForce", "http://schema.org/NotInForce" + "NotYetRecruiting", "http://schema.org/NotYetRecruiting" + "Notary", "http://schema.org/Notary" + "NoteDigitalDocument", "http://schema.org/NoteDigitalDocument" + "Number", "http://schema.org/Number" + "Nursing", "http://schema.org/Nursing" + "NutritionInformation", "http://schema.org/NutritionInformation" + "OTC", "http://schema.org/OTC" + "Observation", "http://schema.org/Observation" + "Observational", "http://schema.org/Observational" + "Obstetric", "http://schema.org/Obstetric" + "Occupation", "http://schema.org/Occupation" + "OccupationalActivity", "http://schema.org/OccupationalActivity" + "OccupationalExperienceRequirements", "http://schema.org/OccupationalExperienceRequirements" + "OccupationalTherapy", "http://schema.org/OccupationalTherapy" + "OceanBodyOfWater", "http://schema.org/OceanBodyOfWater" + "Offer", "http://schema.org/Offer" + "OfferCatalog", "http://schema.org/OfferCatalog" + "OfferForLease", "http://schema.org/OfferForLease" + "OfferForPurchase", "http://schema.org/OfferForPurchase" + "OfferItemCondition", "http://schema.org/OfferItemCondition" + "OfferShippingDetails", "http://schema.org/OfferShippingDetails" + "OfficeEquipmentStore", "http://schema.org/OfficeEquipmentStore" + "OfficialLegalValue", "http://schema.org/OfficialLegalValue" + "OfflineEventAttendanceMode", "http://schema.org/OfflineEventAttendanceMode" + "OfflinePermanently", "http://schema.org/OfflinePermanently" + "OfflineTemporarily", "http://schema.org/OfflineTemporarily" + "OnDemandEvent", "http://schema.org/OnDemandEvent" + "OnSitePickup", "http://schema.org/OnSitePickup" + "Oncologic", "http://schema.org/Oncologic" + "OneTimePayments", "http://schema.org/OneTimePayments" + "Online", "http://schema.org/Online" + "OnlineBusiness", "http://schema.org/OnlineBusiness" + "OnlineEventAttendanceMode", "http://schema.org/OnlineEventAttendanceMode" + "OnlineFull", "http://schema.org/OnlineFull" + "OnlineOnly", "http://schema.org/OnlineOnly" + "OnlineStore", "http://schema.org/OnlineStore" + "OpenTrial", "http://schema.org/OpenTrial" + "OpeningHoursSpecification", "http://schema.org/OpeningHoursSpecification" + "OpinionNewsArticle", "http://schema.org/OpinionNewsArticle" + "Optician", "http://schema.org/Optician" + "Optometric", "http://schema.org/Optometric" + "Order", "http://schema.org/Order" + "OrderAction", "http://schema.org/OrderAction" + "OrderCancelled", "http://schema.org/OrderCancelled" + "OrderDelivered", "http://schema.org/OrderDelivered" + "OrderInTransit", "http://schema.org/OrderInTransit" + "OrderItem", "http://schema.org/OrderItem" + "OrderPaymentDue", "http://schema.org/OrderPaymentDue" + "OrderPickupAvailable", "http://schema.org/OrderPickupAvailable" + "OrderProblem", "http://schema.org/OrderProblem" + "OrderProcessing", "http://schema.org/OrderProcessing" + "OrderReturned", "http://schema.org/OrderReturned" + "OrderStatus", "http://schema.org/OrderStatus" + "Organization", "http://schema.org/Organization" + "OrganizationRole", "http://schema.org/OrganizationRole" + "OrganizeAction", "http://schema.org/OrganizeAction" + "OriginalMediaContent", "http://schema.org/OriginalMediaContent" + "OriginalShippingFees", "http://schema.org/OriginalShippingFees" + "Osteopathic", "http://schema.org/Osteopathic" + "Otolaryngologic", "http://schema.org/Otolaryngologic" + "OutOfStock", "http://schema.org/OutOfStock" + "OutletStore", "http://schema.org/OutletStore" + "OverviewHealthAspect", "http://schema.org/OverviewHealthAspect" + "OwnershipInfo", "http://schema.org/OwnershipInfo" + "PET", "http://schema.org/PET" + "PaidLeave", "http://schema.org/PaidLeave" + "PaintAction", "http://schema.org/PaintAction" + "Painting", "http://schema.org/Painting" + "PalliativeProcedure", "http://schema.org/PalliativeProcedure" + "Paperback", "http://schema.org/Paperback" + "ParcelDelivery", "http://schema.org/ParcelDelivery" + "ParcelService", "http://schema.org/ParcelService" + "ParentAudience", "http://schema.org/ParentAudience" + "ParentalSupport", "http://schema.org/ParentalSupport" + "Park", "http://schema.org/Park" + "ParkingFacility", "http://schema.org/ParkingFacility" + "ParkingMap", "http://schema.org/ParkingMap" + "PartiallyInForce", "http://schema.org/PartiallyInForce" + "Pathology", "http://schema.org/Pathology" + "PathologyTest", "http://schema.org/PathologyTest" + "Patient", "http://schema.org/Patient" + "PatientExperienceHealthAspect", "http://schema.org/PatientExperienceHealthAspect" + "PawnShop", "http://schema.org/PawnShop" + "PayAction", "http://schema.org/PayAction" + "PaymentAutomaticallyApplied", "http://schema.org/PaymentAutomaticallyApplied" + "PaymentCard", "http://schema.org/PaymentCard" + "PaymentChargeSpecification", "http://schema.org/PaymentChargeSpecification" + "PaymentComplete", "http://schema.org/PaymentComplete" + "PaymentDeclined", "http://schema.org/PaymentDeclined" + "PaymentDue", "http://schema.org/PaymentDue" + "PaymentMethod", "http://schema.org/PaymentMethod" + "PaymentPastDue", "http://schema.org/PaymentPastDue" + "PaymentService", "http://schema.org/PaymentService" + "PaymentStatusType", "http://schema.org/PaymentStatusType" + "Pediatric", "http://schema.org/Pediatric" + "PeopleAudience", "http://schema.org/PeopleAudience" + "PercutaneousProcedure", "http://schema.org/PercutaneousProcedure" + "PerformAction", "http://schema.org/PerformAction" + "PerformanceRole", "http://schema.org/PerformanceRole" + "PerformingArtsTheater", "http://schema.org/PerformingArtsTheater" + "PerformingGroup", "http://schema.org/PerformingGroup" + "Periodical", "http://schema.org/Periodical" + "Permit", "http://schema.org/Permit" + "Person", "http://schema.org/Person" + "PetStore", "http://schema.org/PetStore" + "Pharmacy", "http://schema.org/Pharmacy" + "PharmacySpecialty", "http://schema.org/PharmacySpecialty" + "Photograph", "http://schema.org/Photograph" + "PhotographAction", "http://schema.org/PhotographAction" + "PhysicalActivity", "http://schema.org/PhysicalActivity" + "PhysicalActivityCategory", "http://schema.org/PhysicalActivityCategory" + "PhysicalExam", "http://schema.org/PhysicalExam" + "PhysicalTherapy", "http://schema.org/PhysicalTherapy" + "Physician", "http://schema.org/Physician" + "Physiotherapy", "http://schema.org/Physiotherapy" + "Place", "http://schema.org/Place" + "PlaceOfWorship", "http://schema.org/PlaceOfWorship" + "PlaceboControlledTrial", "http://schema.org/PlaceboControlledTrial" + "PlanAction", "http://schema.org/PlanAction" + "PlasticSurgery", "http://schema.org/PlasticSurgery" + "Play", "http://schema.org/Play" + "PlayAction", "http://schema.org/PlayAction" + "PlayGameAction", "http://schema.org/PlayGameAction" + "Playground", "http://schema.org/Playground" + "Plumber", "http://schema.org/Plumber" + "PodcastEpisode", "http://schema.org/PodcastEpisode" + "PodcastSeason", "http://schema.org/PodcastSeason" + "PodcastSeries", "http://schema.org/PodcastSeries" + "Podiatric", "http://schema.org/Podiatric" + "PoliceStation", "http://schema.org/PoliceStation" + "PoliticalParty", "http://schema.org/PoliticalParty" + "Pond", "http://schema.org/Pond" + "PostOffice", "http://schema.org/PostOffice" + "PostalAddress", "http://schema.org/PostalAddress" + "PostalCodeRangeSpecification", "http://schema.org/PostalCodeRangeSpecification" + "Poster", "http://schema.org/Poster" + "PotentialActionStatus", "http://schema.org/PotentialActionStatus" + "PreOrder", "http://schema.org/PreOrder" + "PreOrderAction", "http://schema.org/PreOrderAction" + "PreSale", "http://schema.org/PreSale" + "PregnancyHealthAspect", "http://schema.org/PregnancyHealthAspect" + "PrependAction", "http://schema.org/PrependAction" + "Preschool", "http://schema.org/Preschool" + "PrescriptionOnly", "http://schema.org/PrescriptionOnly" + "PresentationDigitalDocument", "http://schema.org/PresentationDigitalDocument" + "PreventionHealthAspect", "http://schema.org/PreventionHealthAspect" + "PreventionIndication", "http://schema.org/PreventionIndication" + "PriceComponentTypeEnumeration", "http://schema.org/PriceComponentTypeEnumeration" + "PriceSpecification", "http://schema.org/PriceSpecification" + "PriceTypeEnumeration", "http://schema.org/PriceTypeEnumeration" + "PrimaryCare", "http://schema.org/PrimaryCare" + "Prion", "http://schema.org/Prion" + "Product", "http://schema.org/Product" + "ProductCollection", "http://schema.org/ProductCollection" + "ProductGroup", "http://schema.org/ProductGroup" + "ProductModel", "http://schema.org/ProductModel" + "ProductReturnEnumeration", "http://schema.org/ProductReturnEnumeration" + "ProductReturnFiniteReturnWindow", "http://schema.org/ProductReturnFiniteReturnWindow" + "ProductReturnNotPermitted", "http://schema.org/ProductReturnNotPermitted" + "ProductReturnPolicy", "http://schema.org/ProductReturnPolicy" + "ProductReturnUnlimitedWindow", "http://schema.org/ProductReturnUnlimitedWindow" + "ProductReturnUnspecified", "http://schema.org/ProductReturnUnspecified" + "ProfessionalService", "http://schema.org/ProfessionalService" + "ProfilePage", "http://schema.org/ProfilePage" + "PrognosisHealthAspect", "http://schema.org/PrognosisHealthAspect" + "ProgramMembership", "http://schema.org/ProgramMembership" + "Project", "http://schema.org/Project" + "PronounceableText", "http://schema.org/PronounceableText" + "Property", "http://schema.org/Property" + "PropertyValue", "http://schema.org/PropertyValue" + "PropertyValueSpecification", "http://schema.org/PropertyValueSpecification" + "Protein", "http://schema.org/Protein" + "Protozoa", "http://schema.org/Protozoa" + "Psychiatric", "http://schema.org/Psychiatric" + "PsychologicalTreatment", "http://schema.org/PsychologicalTreatment" + "PublicHealth", "http://schema.org/PublicHealth" + "PublicHolidays", "http://schema.org/PublicHolidays" + "PublicSwimmingPool", "http://schema.org/PublicSwimmingPool" + "PublicToilet", "http://schema.org/PublicToilet" + "PublicationEvent", "http://schema.org/PublicationEvent" + "PublicationIssue", "http://schema.org/PublicationIssue" + "PublicationVolume", "http://schema.org/PublicationVolume" + "Pulmonary", "http://schema.org/Pulmonary" + "QAPage", "http://schema.org/QAPage" + "QualitativeValue", "http://schema.org/QualitativeValue" + "QuantitativeValue", "http://schema.org/QuantitativeValue" + "QuantitativeValueDistribution", "http://schema.org/QuantitativeValueDistribution" + "Quantity", "http://schema.org/Quantity" + "Question", "http://schema.org/Question" + "Quiz", "http://schema.org/Quiz" + "Quotation", "http://schema.org/Quotation" + "QuoteAction", "http://schema.org/QuoteAction" + "RVPark", "http://schema.org/RVPark" + "RadiationTherapy", "http://schema.org/RadiationTherapy" + "RadioBroadcastService", "http://schema.org/RadioBroadcastService" + "RadioChannel", "http://schema.org/RadioChannel" + "RadioClip", "http://schema.org/RadioClip" + "RadioEpisode", "http://schema.org/RadioEpisode" + "RadioSeason", "http://schema.org/RadioSeason" + "RadioSeries", "http://schema.org/RadioSeries" + "RadioStation", "http://schema.org/RadioStation" + "Radiography", "http://schema.org/Radiography" + "RandomizedTrial", "http://schema.org/RandomizedTrial" + "Rating", "http://schema.org/Rating" + "ReactAction", "http://schema.org/ReactAction" + "ReadAction", "http://schema.org/ReadAction" + "ReadPermission", "http://schema.org/ReadPermission" + "RealEstateAgent", "http://schema.org/RealEstateAgent" + "RealEstateListing", "http://schema.org/RealEstateListing" + "RearWheelDriveConfiguration", "http://schema.org/RearWheelDriveConfiguration" + "ReceiveAction", "http://schema.org/ReceiveAction" + "Recipe", "http://schema.org/Recipe" + "Recommendation", "http://schema.org/Recommendation" + "RecommendedDoseSchedule", "http://schema.org/RecommendedDoseSchedule" + "Recruiting", "http://schema.org/Recruiting" + "RecyclingCenter", "http://schema.org/RecyclingCenter" + "ReducedRelevanceForChildrenConsideration", "http://schema.org/ReducedRelevanceForChildrenConsideration" + "RefundTypeEnumeration", "http://schema.org/RefundTypeEnumeration" + "RefurbishedCondition", "http://schema.org/RefurbishedCondition" + "RegisterAction", "http://schema.org/RegisterAction" + "Registry", "http://schema.org/Registry" + "ReimbursementCap", "http://schema.org/ReimbursementCap" + "RejectAction", "http://schema.org/RejectAction" + "RelatedTopicsHealthAspect", "http://schema.org/RelatedTopicsHealthAspect" + "RemixAlbum", "http://schema.org/RemixAlbum" + "Renal", "http://schema.org/Renal" + "RentAction", "http://schema.org/RentAction" + "RentalCarReservation", "http://schema.org/RentalCarReservation" + "RentalVehicleUsage", "http://schema.org/RentalVehicleUsage" + "RepaymentSpecification", "http://schema.org/RepaymentSpecification" + "ReplaceAction", "http://schema.org/ReplaceAction" + "ReplyAction", "http://schema.org/ReplyAction" + "Report", "http://schema.org/Report" + "ReportageNewsArticle", "http://schema.org/ReportageNewsArticle" + "ReportedDoseSchedule", "http://schema.org/ReportedDoseSchedule" + "ResearchOrganization", "http://schema.org/ResearchOrganization" + "ResearchProject", "http://schema.org/ResearchProject" + "Researcher", "http://schema.org/Researcher" + "Reservation", "http://schema.org/Reservation" + "ReservationCancelled", "http://schema.org/ReservationCancelled" + "ReservationConfirmed", "http://schema.org/ReservationConfirmed" + "ReservationHold", "http://schema.org/ReservationHold" + "ReservationPackage", "http://schema.org/ReservationPackage" + "ReservationPending", "http://schema.org/ReservationPending" + "ReservationStatusType", "http://schema.org/ReservationStatusType" + "ReserveAction", "http://schema.org/ReserveAction" + "Reservoir", "http://schema.org/Reservoir" + "Residence", "http://schema.org/Residence" + "Resort", "http://schema.org/Resort" + "RespiratoryTherapy", "http://schema.org/RespiratoryTherapy" + "Restaurant", "http://schema.org/Restaurant" + "RestockingFees", "http://schema.org/RestockingFees" + "RestrictedDiet", "http://schema.org/RestrictedDiet" + "ResultsAvailable", "http://schema.org/ResultsAvailable" + "ResultsNotAvailable", "http://schema.org/ResultsNotAvailable" + "ResumeAction", "http://schema.org/ResumeAction" + "Retail", "http://schema.org/Retail" + "ReturnAction", "http://schema.org/ReturnAction" + "ReturnAtKiosk", "http://schema.org/ReturnAtKiosk" + "ReturnByMail", "http://schema.org/ReturnByMail" + "ReturnFeesCustomerResponsibility", "http://schema.org/ReturnFeesCustomerResponsibility" + "ReturnFeesEnumeration", "http://schema.org/ReturnFeesEnumeration" + "ReturnInStore", "http://schema.org/ReturnInStore" + "ReturnLabelCustomerResponsibility", "http://schema.org/ReturnLabelCustomerResponsibility" + "ReturnLabelDownloadAndPrint", "http://schema.org/ReturnLabelDownloadAndPrint" + "ReturnLabelInBox", "http://schema.org/ReturnLabelInBox" + "ReturnLabelSourceEnumeration", "http://schema.org/ReturnLabelSourceEnumeration" + "ReturnMethodEnumeration", "http://schema.org/ReturnMethodEnumeration" + "ReturnShippingFees", "http://schema.org/ReturnShippingFees" + "Review", "http://schema.org/Review" + "ReviewAction", "http://schema.org/ReviewAction" + "ReviewNewsArticle", "http://schema.org/ReviewNewsArticle" + "Rheumatologic", "http://schema.org/Rheumatologic" + "RightHandDriving", "http://schema.org/RightHandDriving" + "RisksOrComplicationsHealthAspect", "http://schema.org/RisksOrComplicationsHealthAspect" + "RiverBodyOfWater", "http://schema.org/RiverBodyOfWater" + "Role", "http://schema.org/Role" + "RoofingContractor", "http://schema.org/RoofingContractor" + "Room", "http://schema.org/Room" + "RsvpAction", "http://schema.org/RsvpAction" + "RsvpResponseMaybe", "http://schema.org/RsvpResponseMaybe" + "RsvpResponseNo", "http://schema.org/RsvpResponseNo" + "RsvpResponseType", "http://schema.org/RsvpResponseType" + "RsvpResponseYes", "http://schema.org/RsvpResponseYes" + "SRP", "http://schema.org/SRP" + "SafetyHealthAspect", "http://schema.org/SafetyHealthAspect" + "SaleEvent", "http://schema.org/SaleEvent" + "SalePrice", "http://schema.org/SalePrice" + "SatireOrParodyContent", "http://schema.org/SatireOrParodyContent" + "SatiricalArticle", "http://schema.org/SatiricalArticle" + "Saturday", "http://schema.org/Saturday" + "Schedule", "http://schema.org/Schedule" + "ScheduleAction", "http://schema.org/ScheduleAction" + "ScholarlyArticle", "http://schema.org/ScholarlyArticle" + "School", "http://schema.org/School" + "SchoolDistrict", "http://schema.org/SchoolDistrict" + "ScreeningEvent", "http://schema.org/ScreeningEvent" + "ScreeningHealthAspect", "http://schema.org/ScreeningHealthAspect" + "Sculpture", "http://schema.org/Sculpture" + "SeaBodyOfWater", "http://schema.org/SeaBodyOfWater" + "SearchAction", "http://schema.org/SearchAction" + "SearchRescueOrganization", "http://schema.org/SearchRescueOrganization" + "SearchResultsPage", "http://schema.org/SearchResultsPage" + "Season", "http://schema.org/Season" + "Seat", "http://schema.org/Seat" + "SeatingMap", "http://schema.org/SeatingMap" + "SeeDoctorHealthAspect", "http://schema.org/SeeDoctorHealthAspect" + "SeekToAction", "http://schema.org/SeekToAction" + "SelfCareHealthAspect", "http://schema.org/SelfCareHealthAspect" + "SelfStorage", "http://schema.org/SelfStorage" + "SellAction", "http://schema.org/SellAction" + "SendAction", "http://schema.org/SendAction" + "Series", "http://schema.org/Series" + "Service", "http://schema.org/Service" + "ServiceChannel", "http://schema.org/ServiceChannel" + "SexualContentConsideration", "http://schema.org/SexualContentConsideration" + "ShareAction", "http://schema.org/ShareAction" + "SheetMusic", "http://schema.org/SheetMusic" + "ShippingDeliveryTime", "http://schema.org/ShippingDeliveryTime" + "ShippingRateSettings", "http://schema.org/ShippingRateSettings" + "ShoeStore", "http://schema.org/ShoeStore" + "ShoppingCenter", "http://schema.org/ShoppingCenter" + "ShortStory", "http://schema.org/ShortStory" + "SideEffectsHealthAspect", "http://schema.org/SideEffectsHealthAspect" + "SingleBlindedTrial", "http://schema.org/SingleBlindedTrial" + "SingleCenterTrial", "http://schema.org/SingleCenterTrial" + "SingleFamilyResidence", "http://schema.org/SingleFamilyResidence" + "SinglePlayer", "http://schema.org/SinglePlayer" + "SingleRelease", "http://schema.org/SingleRelease" + "SiteNavigationElement", "http://schema.org/SiteNavigationElement" + "SizeGroupEnumeration", "http://schema.org/SizeGroupEnumeration" + "SizeSpecification", "http://schema.org/SizeSpecification" + "SizeSystemEnumeration", "http://schema.org/SizeSystemEnumeration" + "SizeSystemImperial", "http://schema.org/SizeSystemImperial" + "SizeSystemMetric", "http://schema.org/SizeSystemMetric" + "SkiResort", "http://schema.org/SkiResort" + "Skin", "http://schema.org/Skin" + "SocialEvent", "http://schema.org/SocialEvent" + "SocialMediaPosting", "http://schema.org/SocialMediaPosting" + "SoftwareApplication", "http://schema.org/SoftwareApplication" + "SoftwareSourceCode", "http://schema.org/SoftwareSourceCode" + "SoldOut", "http://schema.org/SoldOut" + "SolveMathAction", "http://schema.org/SolveMathAction" + "SomeProducts", "http://schema.org/SomeProducts" + "SoundtrackAlbum", "http://schema.org/SoundtrackAlbum" + "SpeakableSpecification", "http://schema.org/SpeakableSpecification" + "SpecialAnnouncement", "http://schema.org/SpecialAnnouncement" + "Specialty", "http://schema.org/Specialty" + "SpeechPathology", "http://schema.org/SpeechPathology" + "SpokenWordAlbum", "http://schema.org/SpokenWordAlbum" + "SportingGoodsStore", "http://schema.org/SportingGoodsStore" + "SportsActivityLocation", "http://schema.org/SportsActivityLocation" + "SportsClub", "http://schema.org/SportsClub" + "SportsEvent", "http://schema.org/SportsEvent" + "SportsOrganization", "http://schema.org/SportsOrganization" + "SportsTeam", "http://schema.org/SportsTeam" + "SpreadsheetDigitalDocument", "http://schema.org/SpreadsheetDigitalDocument" + "StadiumOrArena", "http://schema.org/StadiumOrArena" + "StagedContent", "http://schema.org/StagedContent" + "StagesHealthAspect", "http://schema.org/StagesHealthAspect" + "State", "http://schema.org/State" + "Statement", "http://schema.org/Statement" + "StatisticalPopulation", "http://schema.org/StatisticalPopulation" + "StatisticalVariable", "http://schema.org/StatisticalVariable" + "StatusEnumeration", "http://schema.org/StatusEnumeration" + "SteeringPositionValue", "http://schema.org/SteeringPositionValue" + "Store", "http://schema.org/Store" + "StoreCreditRefund", "http://schema.org/StoreCreditRefund" + "StrengthTraining", "http://schema.org/StrengthTraining" + "StructuredValue", "http://schema.org/StructuredValue" + "StudioAlbum", "http://schema.org/StudioAlbum" + "StupidType", "http://schema.org/StupidType" + "SubscribeAction", "http://schema.org/SubscribeAction" + "Subscription", "http://schema.org/Subscription" + "Substance", "http://schema.org/Substance" + "SubwayStation", "http://schema.org/SubwayStation" + "Suite", "http://schema.org/Suite" + "Sunday", "http://schema.org/Sunday" + "SuperficialAnatomy", "http://schema.org/SuperficialAnatomy" + "Surgical", "http://schema.org/Surgical" + "SurgicalProcedure", "http://schema.org/SurgicalProcedure" + "SuspendAction", "http://schema.org/SuspendAction" + "Suspended", "http://schema.org/Suspended" + "Syllabus", "http://schema.org/Syllabus" + "SymptomsHealthAspect", "http://schema.org/SymptomsHealthAspect" + "Synagogue", "http://schema.org/Synagogue" + "TVClip", "http://schema.org/TVClip" + "TVEpisode", "http://schema.org/TVEpisode" + "TVSeason", "http://schema.org/TVSeason" + "TVSeries", "http://schema.org/TVSeries" + "Table", "http://schema.org/Table" + "TakeAction", "http://schema.org/TakeAction" + "TattooParlor", "http://schema.org/TattooParlor" + "Taxi", "http://schema.org/Taxi" + "TaxiReservation", "http://schema.org/TaxiReservation" + "TaxiService", "http://schema.org/TaxiService" + "TaxiStand", "http://schema.org/TaxiStand" + "TaxiVehicleUsage", "http://schema.org/TaxiVehicleUsage" + "Taxon", "http://schema.org/Taxon" + "TechArticle", "http://schema.org/TechArticle" + "TelevisionChannel", "http://schema.org/TelevisionChannel" + "TelevisionStation", "http://schema.org/TelevisionStation" + "TennisComplex", "http://schema.org/TennisComplex" + "Terminated", "http://schema.org/Terminated" + "Text", "http://schema.org/Text" + "TextDigitalDocument", "http://schema.org/TextDigitalDocument" + "TextObject", "http://schema.org/TextObject" + "TheaterEvent", "http://schema.org/TheaterEvent" + "TheaterGroup", "http://schema.org/TheaterGroup" + "Therapeutic", "http://schema.org/Therapeutic" + "TherapeuticProcedure", "http://schema.org/TherapeuticProcedure" + "Thesis", "http://schema.org/Thesis" + "Thing", "http://schema.org/Thing" + "Throat", "http://schema.org/Throat" + "Thursday", "http://schema.org/Thursday" + "Ticket", "http://schema.org/Ticket" + "TieAction", "http://schema.org/TieAction" + "Time", "http://schema.org/Time" + "TipAction", "http://schema.org/TipAction" + "TireShop", "http://schema.org/TireShop" + "TobaccoNicotineConsideration", "http://schema.org/TobaccoNicotineConsideration" + "TollFree", "http://schema.org/TollFree" + "TouristAttraction", "http://schema.org/TouristAttraction" + "TouristDestination", "http://schema.org/TouristDestination" + "TouristInformationCenter", "http://schema.org/TouristInformationCenter" + "TouristTrip", "http://schema.org/TouristTrip" + "Toxicologic", "http://schema.org/Toxicologic" + "ToyStore", "http://schema.org/ToyStore" + "TrackAction", "http://schema.org/TrackAction" + "TradeAction", "http://schema.org/TradeAction" + "TraditionalChinese", "http://schema.org/TraditionalChinese" + "TrainReservation", "http://schema.org/TrainReservation" + "TrainStation", "http://schema.org/TrainStation" + "TrainTrip", "http://schema.org/TrainTrip" + "TransferAction", "http://schema.org/TransferAction" + "TransformedContent", "http://schema.org/TransformedContent" + "TransitMap", "http://schema.org/TransitMap" + "TravelAction", "http://schema.org/TravelAction" + "TravelAgency", "http://schema.org/TravelAgency" + "TreatmentIndication", "http://schema.org/TreatmentIndication" + "TreatmentsHealthAspect", "http://schema.org/TreatmentsHealthAspect" + "Trip", "http://schema.org/Trip" + "TripleBlindedTrial", "http://schema.org/TripleBlindedTrial" + "True", "http://schema.org/True" + "Tuesday", "http://schema.org/Tuesday" + "TypeAndQuantityNode", "http://schema.org/TypeAndQuantityNode" + "TypesHealthAspect", "http://schema.org/TypesHealthAspect" + "UKNonprofitType", "http://schema.org/UKNonprofitType" + "UKTrust", "http://schema.org/UKTrust" + "URL", "http://schema.org/URL" + "USNonprofitType", "http://schema.org/USNonprofitType" + "Ultrasound", "http://schema.org/Ultrasound" + "UnRegisterAction", "http://schema.org/UnRegisterAction" + "UnclassifiedAdultConsideration", "http://schema.org/UnclassifiedAdultConsideration" + "UnemploymentSupport", "http://schema.org/UnemploymentSupport" + "UnincorporatedAssociationCharity", "http://schema.org/UnincorporatedAssociationCharity" + "UnitPriceSpecification", "http://schema.org/UnitPriceSpecification" + "UnofficialLegalValue", "http://schema.org/UnofficialLegalValue" + "UpdateAction", "http://schema.org/UpdateAction" + "Urologic", "http://schema.org/Urologic" + "UsageOrScheduleHealthAspect", "http://schema.org/UsageOrScheduleHealthAspect" + "UseAction", "http://schema.org/UseAction" + "UsedCondition", "http://schema.org/UsedCondition" + "UserBlocks", "http://schema.org/UserBlocks" + "UserCheckins", "http://schema.org/UserCheckins" + "UserComments", "http://schema.org/UserComments" + "UserDownloads", "http://schema.org/UserDownloads" + "UserInteraction", "http://schema.org/UserInteraction" + "UserLikes", "http://schema.org/UserLikes" + "UserPageVisits", "http://schema.org/UserPageVisits" + "UserPlays", "http://schema.org/UserPlays" + "UserPlusOnes", "http://schema.org/UserPlusOnes" + "UserReview", "http://schema.org/UserReview" + "UserTweets", "http://schema.org/UserTweets" + "VacationRental", "http://schema.org/VacationRental" + "VeganDiet", "http://schema.org/VeganDiet" + "VegetarianDiet", "http://schema.org/VegetarianDiet" + "Vehicle", "http://schema.org/Vehicle" + "Vein", "http://schema.org/Vein" + "VenueMap", "http://schema.org/VenueMap" + "Vessel", "http://schema.org/Vessel" + "VeterinaryCare", "http://schema.org/VeterinaryCare" + "VideoGallery", "http://schema.org/VideoGallery" + "VideoGame", "http://schema.org/VideoGame" + "VideoGameClip", "http://schema.org/VideoGameClip" + "VideoGameSeries", "http://schema.org/VideoGameSeries" + "VideoObject", "http://schema.org/VideoObject" + "VideoObjectSnapshot", "http://schema.org/VideoObjectSnapshot" + "ViewAction", "http://schema.org/ViewAction" + "VinylFormat", "http://schema.org/VinylFormat" + "ViolenceConsideration", "http://schema.org/ViolenceConsideration" + "VirtualLocation", "http://schema.org/VirtualLocation" + "Virus", "http://schema.org/Virus" + "VisualArtsEvent", "http://schema.org/VisualArtsEvent" + "VisualArtwork", "http://schema.org/VisualArtwork" + "VitalSign", "http://schema.org/VitalSign" + "Volcano", "http://schema.org/Volcano" + "VoteAction", "http://schema.org/VoteAction" + "WPAdBlock", "http://schema.org/WPAdBlock" + "WPFooter", "http://schema.org/WPFooter" + "WPHeader", "http://schema.org/WPHeader" + "WPSideBar", "http://schema.org/WPSideBar" + "WantAction", "http://schema.org/WantAction" + "WarrantyPromise", "http://schema.org/WarrantyPromise" + "WarrantyScope", "http://schema.org/WarrantyScope" + "WatchAction", "http://schema.org/WatchAction" + "Waterfall", "http://schema.org/Waterfall" + "WeaponConsideration", "http://schema.org/WeaponConsideration" + "WearAction", "http://schema.org/WearAction" + "WearableMeasurementBack", "http://schema.org/WearableMeasurementBack" + "WearableMeasurementChestOrBust", "http://schema.org/WearableMeasurementChestOrBust" + "WearableMeasurementCollar", "http://schema.org/WearableMeasurementCollar" + "WearableMeasurementCup", "http://schema.org/WearableMeasurementCup" + "WearableMeasurementHeight", "http://schema.org/WearableMeasurementHeight" + "WearableMeasurementHips", "http://schema.org/WearableMeasurementHips" + "WearableMeasurementInseam", "http://schema.org/WearableMeasurementInseam" + "WearableMeasurementLength", "http://schema.org/WearableMeasurementLength" + "WearableMeasurementOutsideLeg", "http://schema.org/WearableMeasurementOutsideLeg" + "WearableMeasurementSleeve", "http://schema.org/WearableMeasurementSleeve" + "WearableMeasurementTypeEnumeration", "http://schema.org/WearableMeasurementTypeEnumeration" + "WearableMeasurementWaist", "http://schema.org/WearableMeasurementWaist" + "WearableMeasurementWidth", "http://schema.org/WearableMeasurementWidth" + "WearableSizeGroupBig", "http://schema.org/WearableSizeGroupBig" + "WearableSizeGroupBoys", "http://schema.org/WearableSizeGroupBoys" + "WearableSizeGroupEnumeration", "http://schema.org/WearableSizeGroupEnumeration" + "WearableSizeGroupExtraShort", "http://schema.org/WearableSizeGroupExtraShort" + "WearableSizeGroupExtraTall", "http://schema.org/WearableSizeGroupExtraTall" + "WearableSizeGroupGirls", "http://schema.org/WearableSizeGroupGirls" + "WearableSizeGroupHusky", "http://schema.org/WearableSizeGroupHusky" + "WearableSizeGroupInfants", "http://schema.org/WearableSizeGroupInfants" + "WearableSizeGroupJuniors", "http://schema.org/WearableSizeGroupJuniors" + "WearableSizeGroupMaternity", "http://schema.org/WearableSizeGroupMaternity" + "WearableSizeGroupMens", "http://schema.org/WearableSizeGroupMens" + "WearableSizeGroupMisses", "http://schema.org/WearableSizeGroupMisses" + "WearableSizeGroupPetite", "http://schema.org/WearableSizeGroupPetite" + "WearableSizeGroupPlus", "http://schema.org/WearableSizeGroupPlus" + "WearableSizeGroupRegular", "http://schema.org/WearableSizeGroupRegular" + "WearableSizeGroupShort", "http://schema.org/WearableSizeGroupShort" + "WearableSizeGroupTall", "http://schema.org/WearableSizeGroupTall" + "WearableSizeGroupWomens", "http://schema.org/WearableSizeGroupWomens" + "WearableSizeSystemAU", "http://schema.org/WearableSizeSystemAU" + "WearableSizeSystemBR", "http://schema.org/WearableSizeSystemBR" + "WearableSizeSystemCN", "http://schema.org/WearableSizeSystemCN" + "WearableSizeSystemContinental", "http://schema.org/WearableSizeSystemContinental" + "WearableSizeSystemDE", "http://schema.org/WearableSizeSystemDE" + "WearableSizeSystemEN13402", "http://schema.org/WearableSizeSystemEN13402" + "WearableSizeSystemEnumeration", "http://schema.org/WearableSizeSystemEnumeration" + "WearableSizeSystemEurope", "http://schema.org/WearableSizeSystemEurope" + "WearableSizeSystemFR", "http://schema.org/WearableSizeSystemFR" + "WearableSizeSystemGS1", "http://schema.org/WearableSizeSystemGS1" + "WearableSizeSystemIT", "http://schema.org/WearableSizeSystemIT" + "WearableSizeSystemJP", "http://schema.org/WearableSizeSystemJP" + "WearableSizeSystemMX", "http://schema.org/WearableSizeSystemMX" + "WearableSizeSystemUK", "http://schema.org/WearableSizeSystemUK" + "WearableSizeSystemUS", "http://schema.org/WearableSizeSystemUS" + "WebAPI", "http://schema.org/WebAPI" + "WebApplication", "http://schema.org/WebApplication" + "WebContent", "http://schema.org/WebContent" + "WebPage", "http://schema.org/WebPage" + "WebPageElement", "http://schema.org/WebPageElement" + "WebSite", "http://schema.org/WebSite" + "Wednesday", "http://schema.org/Wednesday" + "WesternConventional", "http://schema.org/WesternConventional" + "Wholesale", "http://schema.org/Wholesale" + "WholesaleStore", "http://schema.org/WholesaleStore" + "WinAction", "http://schema.org/WinAction" + "Winery", "http://schema.org/Winery" + "Withdrawn", "http://schema.org/Withdrawn" + "WorkBasedProgram", "http://schema.org/WorkBasedProgram" + "WorkersUnion", "http://schema.org/WorkersUnion" + "WriteAction", "http://schema.org/WriteAction" + "WritePermission", "http://schema.org/WritePermission" + "XPathType", "http://schema.org/XPathType" + "XRay", "http://schema.org/XRay" + "ZoneBoardingPolicy", "http://schema.org/ZoneBoardingPolicy" + "Zoo", "http://schema.org/Zoo" + "about", "http://schema.org/about" + "abridged", "http://schema.org/abridged" + "abstract", "http://schema.org/abstract" + "accelerationTime", "http://schema.org/accelerationTime" + "acceptedAnswer", "http://schema.org/acceptedAnswer" + "acceptedOffer", "http://schema.org/acceptedOffer" + "acceptedPaymentMethod", "http://schema.org/acceptedPaymentMethod" + "acceptsReservations", "http://schema.org/acceptsReservations" + "accessCode", "http://schema.org/accessCode" + "accessMode", "http://schema.org/accessMode" + "accessModeSufficient", "http://schema.org/accessModeSufficient" + "accessibilityAPI", "http://schema.org/accessibilityAPI" + "accessibilityControl", "http://schema.org/accessibilityControl" + "accessibilityFeature", "http://schema.org/accessibilityFeature" + "accessibilityHazard", "http://schema.org/accessibilityHazard" + "accessibilitySummary", "http://schema.org/accessibilitySummary" + "accommodationCategory", "http://schema.org/accommodationCategory" + "accommodationFloorPlan", "http://schema.org/accommodationFloorPlan" + "accountId", "http://schema.org/accountId" + "accountMinimumInflow", "http://schema.org/accountMinimumInflow" + "accountOverdraftLimit", "http://schema.org/accountOverdraftLimit" + "accountablePerson", "http://schema.org/accountablePerson" + "acquireLicensePage", "http://schema.org/acquireLicensePage" + "acquiredFrom", "http://schema.org/acquiredFrom" + "acrissCode", "http://schema.org/acrissCode" + "actionAccessibilityRequirement", "http://schema.org/actionAccessibilityRequirement" + "actionApplication", "http://schema.org/actionApplication" + "actionOption", "http://schema.org/actionOption" + "actionPlatform", "http://schema.org/actionPlatform" + "actionStatus", "http://schema.org/actionStatus" + "actionableFeedbackPolicy", "http://schema.org/actionableFeedbackPolicy" + "activeIngredient", "http://schema.org/activeIngredient" + "activityDuration", "http://schema.org/activityDuration" + "activityFrequency", "http://schema.org/activityFrequency" + "actor", "http://schema.org/actor" + "actors", "http://schema.org/actors" + "addOn", "http://schema.org/addOn" + "additionalName", "http://schema.org/additionalName" + "additionalNumberOfGuests", "http://schema.org/additionalNumberOfGuests" + "additionalProperty", "http://schema.org/additionalProperty" + "additionalType", "http://schema.org/additionalType" + "additionalVariable", "http://schema.org/additionalVariable" + "address", "http://schema.org/address" + "addressCountry", "http://schema.org/addressCountry" + "addressLocality", "http://schema.org/addressLocality" + "addressRegion", "http://schema.org/addressRegion" + "administrationRoute", "http://schema.org/administrationRoute" + "advanceBookingRequirement", "http://schema.org/advanceBookingRequirement" + "adverseOutcome", "http://schema.org/adverseOutcome" + "affectedBy", "http://schema.org/affectedBy" + "affiliation", "http://schema.org/affiliation" + "afterMedia", "http://schema.org/afterMedia" + "agent", "http://schema.org/agent" + "aggregateRating", "http://schema.org/aggregateRating" + "aircraft", "http://schema.org/aircraft" + "album", "http://schema.org/album" + "albumProductionType", "http://schema.org/albumProductionType" + "albumRelease", "http://schema.org/albumRelease" + "albumReleaseType", "http://schema.org/albumReleaseType" + "albums", "http://schema.org/albums" + "alcoholWarning", "http://schema.org/alcoholWarning" + "algorithm", "http://schema.org/algorithm" + "alignmentType", "http://schema.org/alignmentType" + "alternateName", "http://schema.org/alternateName" + "alternativeHeadline", "http://schema.org/alternativeHeadline" + "alternativeOf", "http://schema.org/alternativeOf" + "alumni", "http://schema.org/alumni" + "alumniOf", "http://schema.org/alumniOf" + "amenityFeature", "http://schema.org/amenityFeature" + "amount", "http://schema.org/amount" + "amountOfThisGood", "http://schema.org/amountOfThisGood" + "announcementLocation", "http://schema.org/announcementLocation" + "annualPercentageRate", "http://schema.org/annualPercentageRate" + "answerCount", "http://schema.org/answerCount" + "answerExplanation", "http://schema.org/answerExplanation" + "antagonist", "http://schema.org/antagonist" + "appearance", "http://schema.org/appearance" + "applicableCountry", "http://schema.org/applicableCountry" + "applicableLocation", "http://schema.org/applicableLocation" + "applicantLocationRequirements", "http://schema.org/applicantLocationRequirements" + "application", "http://schema.org/application" + "applicationCategory", "http://schema.org/applicationCategory" + "applicationContact", "http://schema.org/applicationContact" + "applicationDeadline", "http://schema.org/applicationDeadline" + "applicationStartDate", "http://schema.org/applicationStartDate" + "applicationSubCategory", "http://schema.org/applicationSubCategory" + "applicationSuite", "http://schema.org/applicationSuite" + "appliesToDeliveryMethod", "http://schema.org/appliesToDeliveryMethod" + "appliesToPaymentMethod", "http://schema.org/appliesToPaymentMethod" + "archiveHeld", "http://schema.org/archiveHeld" + "archivedAt", "http://schema.org/archivedAt" + "area", "http://schema.org/area" + "areaServed", "http://schema.org/areaServed" + "arrivalAirport", "http://schema.org/arrivalAirport" + "arrivalBoatTerminal", "http://schema.org/arrivalBoatTerminal" + "arrivalBusStop", "http://schema.org/arrivalBusStop" + "arrivalGate", "http://schema.org/arrivalGate" + "arrivalPlatform", "http://schema.org/arrivalPlatform" + "arrivalStation", "http://schema.org/arrivalStation" + "arrivalTerminal", "http://schema.org/arrivalTerminal" + "arrivalTime", "http://schema.org/arrivalTime" + "artEdition", "http://schema.org/artEdition" + "artMedium", "http://schema.org/artMedium" + "arterialBranch", "http://schema.org/arterialBranch" + "artform", "http://schema.org/artform" + "articleBody", "http://schema.org/articleBody" + "articleSection", "http://schema.org/articleSection" + "artist", "http://schema.org/artist" + "artworkSurface", "http://schema.org/artworkSurface" + "asin", "http://schema.org/asin" + "aspect", "http://schema.org/aspect" + "assembly", "http://schema.org/assembly" + "assemblyVersion", "http://schema.org/assemblyVersion" + "assesses", "http://schema.org/assesses" + "associatedAnatomy", "http://schema.org/associatedAnatomy" + "associatedArticle", "http://schema.org/associatedArticle" + "associatedClaimReview", "http://schema.org/associatedClaimReview" + "associatedDisease", "http://schema.org/associatedDisease" + "associatedMedia", "http://schema.org/associatedMedia" + "associatedMediaReview", "http://schema.org/associatedMediaReview" + "associatedPathophysiology", "http://schema.org/associatedPathophysiology" + "associatedReview", "http://schema.org/associatedReview" + "athlete", "http://schema.org/athlete" + "attendee", "http://schema.org/attendee" + "attendees", "http://schema.org/attendees" + "audience", "http://schema.org/audience" + "audienceType", "http://schema.org/audienceType" + "audio", "http://schema.org/audio" + "authenticator", "http://schema.org/authenticator" + "author", "http://schema.org/author" + "availability", "http://schema.org/availability" + "availabilityEnds", "http://schema.org/availabilityEnds" + "availabilityStarts", "http://schema.org/availabilityStarts" + "availableAtOrFrom", "http://schema.org/availableAtOrFrom" + "availableChannel", "http://schema.org/availableChannel" + "availableDeliveryMethod", "http://schema.org/availableDeliveryMethod" + "availableFrom", "http://schema.org/availableFrom" + "availableIn", "http://schema.org/availableIn" + "availableLanguage", "http://schema.org/availableLanguage" + "availableOnDevice", "http://schema.org/availableOnDevice" + "availableService", "http://schema.org/availableService" + "availableStrength", "http://schema.org/availableStrength" + "availableTest", "http://schema.org/availableTest" + "availableThrough", "http://schema.org/availableThrough" + "award", "http://schema.org/award" + "awards", "http://schema.org/awards" + "awayTeam", "http://schema.org/awayTeam" + "backstory", "http://schema.org/backstory" + "bankAccountType", "http://schema.org/bankAccountType" + "baseSalary", "http://schema.org/baseSalary" + "bccRecipient", "http://schema.org/bccRecipient" + "bed", "http://schema.org/bed" + "beforeMedia", "http://schema.org/beforeMedia" + "beneficiaryBank", "http://schema.org/beneficiaryBank" + "benefits", "http://schema.org/benefits" + "benefitsSummaryUrl", "http://schema.org/benefitsSummaryUrl" + "bestRating", "http://schema.org/bestRating" + "billingAddress", "http://schema.org/billingAddress" + "billingDuration", "http://schema.org/billingDuration" + "billingIncrement", "http://schema.org/billingIncrement" + "billingPeriod", "http://schema.org/billingPeriod" + "billingStart", "http://schema.org/billingStart" + "bioChemInteraction", "http://schema.org/bioChemInteraction" + "bioChemSimilarity", "http://schema.org/bioChemSimilarity" + "biologicalRole", "http://schema.org/biologicalRole" + "biomechnicalClass", "http://schema.org/biomechnicalClass" + "birthDate", "http://schema.org/birthDate" + "birthPlace", "http://schema.org/birthPlace" + "bitrate", "http://schema.org/bitrate" + "blogPost", "http://schema.org/blogPost" + "blogPosts", "http://schema.org/blogPosts" + "bloodSupply", "http://schema.org/bloodSupply" + "boardingGroup", "http://schema.org/boardingGroup" + "boardingPolicy", "http://schema.org/boardingPolicy" + "bodyLocation", "http://schema.org/bodyLocation" + "bodyType", "http://schema.org/bodyType" + "bookEdition", "http://schema.org/bookEdition" + "bookFormat", "http://schema.org/bookFormat" + "bookingAgent", "http://schema.org/bookingAgent" + "bookingTime", "http://schema.org/bookingTime" + "borrower", "http://schema.org/borrower" + "box", "http://schema.org/box" + "branch", "http://schema.org/branch" + "branchCode", "http://schema.org/branchCode" + "branchOf", "http://schema.org/branchOf" + "brand", "http://schema.org/brand" + "breadcrumb", "http://schema.org/breadcrumb" + "breastfeedingWarning", "http://schema.org/breastfeedingWarning" + "broadcastAffiliateOf", "http://schema.org/broadcastAffiliateOf" + "broadcastChannelId", "http://schema.org/broadcastChannelId" + "broadcastDisplayName", "http://schema.org/broadcastDisplayName" + "broadcastFrequency", "http://schema.org/broadcastFrequency" + "broadcastFrequencyValue", "http://schema.org/broadcastFrequencyValue" + "broadcastOfEvent", "http://schema.org/broadcastOfEvent" + "broadcastServiceTier", "http://schema.org/broadcastServiceTier" + "broadcastSignalModulation", "http://schema.org/broadcastSignalModulation" + "broadcastSubChannel", "http://schema.org/broadcastSubChannel" + "broadcastTimezone", "http://schema.org/broadcastTimezone" + "broadcaster", "http://schema.org/broadcaster" + "broker", "http://schema.org/broker" + "browserRequirements", "http://schema.org/browserRequirements" + "busName", "http://schema.org/busName" + "busNumber", "http://schema.org/busNumber" + "businessDays", "http://schema.org/businessDays" + "businessFunction", "http://schema.org/businessFunction" + "buyer", "http://schema.org/buyer" + "byArtist", "http://schema.org/byArtist" + "byDay", "http://schema.org/byDay" + "byMonth", "http://schema.org/byMonth" + "byMonthDay", "http://schema.org/byMonthDay" + "byMonthWeek", "http://schema.org/byMonthWeek" + "callSign", "http://schema.org/callSign" + "calories", "http://schema.org/calories" + "candidate", "http://schema.org/candidate" + "caption", "http://schema.org/caption" + "carbohydrateContent", "http://schema.org/carbohydrateContent" + "cargoVolume", "http://schema.org/cargoVolume" + "carrier", "http://schema.org/carrier" + "carrierRequirements", "http://schema.org/carrierRequirements" + "cashBack", "http://schema.org/cashBack" + "catalog", "http://schema.org/catalog" + "catalogNumber", "http://schema.org/catalogNumber" + "category", "http://schema.org/category" + "causeOf", "http://schema.org/causeOf" + "ccRecipient", "http://schema.org/ccRecipient" + "character", "http://schema.org/character" + "characterAttribute", "http://schema.org/characterAttribute" + "characterName", "http://schema.org/characterName" + "cheatCode", "http://schema.org/cheatCode" + "checkinTime", "http://schema.org/checkinTime" + "checkoutPageURLTemplate", "http://schema.org/checkoutPageURLTemplate" + "checkoutTime", "http://schema.org/checkoutTime" + "chemicalComposition", "http://schema.org/chemicalComposition" + "chemicalRole", "http://schema.org/chemicalRole" + "childMaxAge", "http://schema.org/childMaxAge" + "childMinAge", "http://schema.org/childMinAge" + "childTaxon", "http://schema.org/childTaxon" + "children", "http://schema.org/children" + "cholesterolContent", "http://schema.org/cholesterolContent" + "circle", "http://schema.org/circle" + "citation", "http://schema.org/citation" + "claimInterpreter", "http://schema.org/claimInterpreter" + "claimReviewed", "http://schema.org/claimReviewed" + "clincalPharmacology", "http://schema.org/clincalPharmacology" + "clinicalPharmacology", "http://schema.org/clinicalPharmacology" + "clipNumber", "http://schema.org/clipNumber" + "closes", "http://schema.org/closes" + "coach", "http://schema.org/coach" + "code", "http://schema.org/code" + "codeRepository", "http://schema.org/codeRepository" + "codeSampleType", "http://schema.org/codeSampleType" + "codeValue", "http://schema.org/codeValue" + "codingSystem", "http://schema.org/codingSystem" + "colleague", "http://schema.org/colleague" + "colleagues", "http://schema.org/colleagues" + "collection", "http://schema.org/collection" + "collectionSize", "http://schema.org/collectionSize" + "color", "http://schema.org/color" + "colorist", "http://schema.org/colorist" + "comment", "http://schema.org/comment" + "commentCount", "http://schema.org/commentCount" + "commentText", "http://schema.org/commentText" + "commentTime", "http://schema.org/commentTime" + "competencyRequired", "http://schema.org/competencyRequired" + "competitor", "http://schema.org/competitor" + "composer", "http://schema.org/composer" + "comprisedOf", "http://schema.org/comprisedOf" + "conditionsOfAccess", "http://schema.org/conditionsOfAccess" + "confirmationNumber", "http://schema.org/confirmationNumber" + "connectedTo", "http://schema.org/connectedTo" + "constraintProperty", "http://schema.org/constraintProperty" + "contactOption", "http://schema.org/contactOption" + "contactPoint", "http://schema.org/contactPoint" + "contactPoints", "http://schema.org/contactPoints" + "contactType", "http://schema.org/contactType" + "contactlessPayment", "http://schema.org/contactlessPayment" + "containedIn", "http://schema.org/containedIn" + "containedInPlace", "http://schema.org/containedInPlace" + "containsPlace", "http://schema.org/containsPlace" + "containsSeason", "http://schema.org/containsSeason" + "contentLocation", "http://schema.org/contentLocation" + "contentRating", "http://schema.org/contentRating" + "contentReferenceTime", "http://schema.org/contentReferenceTime" + "contentSize", "http://schema.org/contentSize" + "contentType", "http://schema.org/contentType" + "contentUrl", "http://schema.org/contentUrl" + "contraindication", "http://schema.org/contraindication" + "contributor", "http://schema.org/contributor" + "cookTime", "http://schema.org/cookTime" + "cookingMethod", "http://schema.org/cookingMethod" + "copyrightHolder", "http://schema.org/copyrightHolder" + "copyrightNotice", "http://schema.org/copyrightNotice" + "copyrightYear", "http://schema.org/copyrightYear" + "correction", "http://schema.org/correction" + "correctionsPolicy", "http://schema.org/correctionsPolicy" + "costCategory", "http://schema.org/costCategory" + "costCurrency", "http://schema.org/costCurrency" + "costOrigin", "http://schema.org/costOrigin" + "costPerUnit", "http://schema.org/costPerUnit" + "countriesNotSupported", "http://schema.org/countriesNotSupported" + "countriesSupported", "http://schema.org/countriesSupported" + "countryOfAssembly", "http://schema.org/countryOfAssembly" + "countryOfLastProcessing", "http://schema.org/countryOfLastProcessing" + "countryOfOrigin", "http://schema.org/countryOfOrigin" + "course", "http://schema.org/course" + "courseCode", "http://schema.org/courseCode" + "courseMode", "http://schema.org/courseMode" + "coursePrerequisites", "http://schema.org/coursePrerequisites" + "courseSchedule", "http://schema.org/courseSchedule" + "courseWorkload", "http://schema.org/courseWorkload" + "coverageEndTime", "http://schema.org/coverageEndTime" + "coverageStartTime", "http://schema.org/coverageStartTime" + "creativeWorkStatus", "http://schema.org/creativeWorkStatus" + "creator", "http://schema.org/creator" + "credentialCategory", "http://schema.org/credentialCategory" + "creditText", "http://schema.org/creditText" + "creditedTo", "http://schema.org/creditedTo" + "cssSelector", "http://schema.org/cssSelector" + "currenciesAccepted", "http://schema.org/currenciesAccepted" + "currency", "http://schema.org/currency" + "currentExchangeRate", "http://schema.org/currentExchangeRate" + "customer", "http://schema.org/customer" + "customerRemorseReturnFees", "http://schema.org/customerRemorseReturnFees" + "customerRemorseReturnLabelSource", "http://schema.org/customerRemorseReturnLabelSource" + "customerRemorseReturnShippingFeesAmount", "http://schema.org/customerRemorseReturnShippingFeesAmount" + "cutoffTime", "http://schema.org/cutoffTime" + "cvdCollectionDate", "http://schema.org/cvdCollectionDate" + "cvdFacilityCounty", "http://schema.org/cvdFacilityCounty" + "cvdFacilityId", "http://schema.org/cvdFacilityId" + "cvdNumBeds", "http://schema.org/cvdNumBeds" + "cvdNumBedsOcc", "http://schema.org/cvdNumBedsOcc" + "cvdNumC19Died", "http://schema.org/cvdNumC19Died" + "cvdNumC19HOPats", "http://schema.org/cvdNumC19HOPats" + "cvdNumC19HospPats", "http://schema.org/cvdNumC19HospPats" + "cvdNumC19MechVentPats", "http://schema.org/cvdNumC19MechVentPats" + "cvdNumC19OFMechVentPats", "http://schema.org/cvdNumC19OFMechVentPats" + "cvdNumC19OverflowPats", "http://schema.org/cvdNumC19OverflowPats" + "cvdNumICUBeds", "http://schema.org/cvdNumICUBeds" + "cvdNumICUBedsOcc", "http://schema.org/cvdNumICUBedsOcc" + "cvdNumTotBeds", "http://schema.org/cvdNumTotBeds" + "cvdNumVent", "http://schema.org/cvdNumVent" + "cvdNumVentUse", "http://schema.org/cvdNumVentUse" + "dataFeedElement", "http://schema.org/dataFeedElement" + "dataset", "http://schema.org/dataset" + "datasetTimeInterval", "http://schema.org/datasetTimeInterval" + "dateCreated", "http://schema.org/dateCreated" + "dateDeleted", "http://schema.org/dateDeleted" + "dateIssued", "http://schema.org/dateIssued" + "dateModified", "http://schema.org/dateModified" + "datePosted", "http://schema.org/datePosted" + "datePublished", "http://schema.org/datePublished" + "dateRead", "http://schema.org/dateRead" + "dateReceived", "http://schema.org/dateReceived" + "dateSent", "http://schema.org/dateSent" + "dateVehicleFirstRegistered", "http://schema.org/dateVehicleFirstRegistered" + "dateline", "http://schema.org/dateline" + "dayOfWeek", "http://schema.org/dayOfWeek" + "deathDate", "http://schema.org/deathDate" + "deathPlace", "http://schema.org/deathPlace" + "defaultValue", "http://schema.org/defaultValue" + "deliveryAddress", "http://schema.org/deliveryAddress" + "deliveryLeadTime", "http://schema.org/deliveryLeadTime" + "deliveryMethod", "http://schema.org/deliveryMethod" + "deliveryStatus", "http://schema.org/deliveryStatus" + "deliveryTime", "http://schema.org/deliveryTime" + "department", "http://schema.org/department" + "departureAirport", "http://schema.org/departureAirport" + "departureBoatTerminal", "http://schema.org/departureBoatTerminal" + "departureBusStop", "http://schema.org/departureBusStop" + "departureGate", "http://schema.org/departureGate" + "departurePlatform", "http://schema.org/departurePlatform" + "departureStation", "http://schema.org/departureStation" + "departureTerminal", "http://schema.org/departureTerminal" + "departureTime", "http://schema.org/departureTime" + "dependencies", "http://schema.org/dependencies" + "depth", "http://schema.org/depth" + "description", "http://schema.org/description" + "device", "http://schema.org/device" + "diagnosis", "http://schema.org/diagnosis" + "diagram", "http://schema.org/diagram" + "diet", "http://schema.org/diet" + "dietFeatures", "http://schema.org/dietFeatures" + "differentialDiagnosis", "http://schema.org/differentialDiagnosis" + "directApply", "http://schema.org/directApply" + "director", "http://schema.org/director" + "directors", "http://schema.org/directors" + "disambiguatingDescription", "http://schema.org/disambiguatingDescription" + "discount", "http://schema.org/discount" + "discountCode", "http://schema.org/discountCode" + "discountCurrency", "http://schema.org/discountCurrency" + "discusses", "http://schema.org/discusses" + "discussionUrl", "http://schema.org/discussionUrl" + "diseasePreventionInfo", "http://schema.org/diseasePreventionInfo" + "diseaseSpreadStatistics", "http://schema.org/diseaseSpreadStatistics" + "dissolutionDate", "http://schema.org/dissolutionDate" + "distance", "http://schema.org/distance" + "distinguishingSign", "http://schema.org/distinguishingSign" + "distribution", "http://schema.org/distribution" + "diversityPolicy", "http://schema.org/diversityPolicy" + "diversityStaffingReport", "http://schema.org/diversityStaffingReport" + "documentation", "http://schema.org/documentation" + "doesNotShip", "http://schema.org/doesNotShip" + "domainIncludes", "http://schema.org/domainIncludes" + "domiciledMortgage", "http://schema.org/domiciledMortgage" + "doorTime", "http://schema.org/doorTime" + "dosageForm", "http://schema.org/dosageForm" + "doseSchedule", "http://schema.org/doseSchedule" + "doseUnit", "http://schema.org/doseUnit" + "doseValue", "http://schema.org/doseValue" + "downPayment", "http://schema.org/downPayment" + "downloadUrl", "http://schema.org/downloadUrl" + "downvoteCount", "http://schema.org/downvoteCount" + "drainsTo", "http://schema.org/drainsTo" + "driveWheelConfiguration", "http://schema.org/driveWheelConfiguration" + "dropoffLocation", "http://schema.org/dropoffLocation" + "dropoffTime", "http://schema.org/dropoffTime" + "drug", "http://schema.org/drug" + "drugClass", "http://schema.org/drugClass" + "drugUnit", "http://schema.org/drugUnit" + "duns", "http://schema.org/duns" + "duplicateTherapy", "http://schema.org/duplicateTherapy" + "duration", "http://schema.org/duration" + "durationOfWarranty", "http://schema.org/durationOfWarranty" + "duringMedia", "http://schema.org/duringMedia" + "earlyPrepaymentPenalty", "http://schema.org/earlyPrepaymentPenalty" + "editEIDR", "http://schema.org/editEIDR" + "editor", "http://schema.org/editor" + "eduQuestionType", "http://schema.org/eduQuestionType" + "educationRequirements", "http://schema.org/educationRequirements" + "educationalAlignment", "http://schema.org/educationalAlignment" + "educationalCredentialAwarded", "http://schema.org/educationalCredentialAwarded" + "educationalFramework", "http://schema.org/educationalFramework" + "educationalLevel", "http://schema.org/educationalLevel" + "educationalProgramMode", "http://schema.org/educationalProgramMode" + "educationalRole", "http://schema.org/educationalRole" + "educationalUse", "http://schema.org/educationalUse" + "elevation", "http://schema.org/elevation" + "eligibilityToWorkRequirement", "http://schema.org/eligibilityToWorkRequirement" + "eligibleCustomerType", "http://schema.org/eligibleCustomerType" + "eligibleDuration", "http://schema.org/eligibleDuration" + "eligibleQuantity", "http://schema.org/eligibleQuantity" + "eligibleRegion", "http://schema.org/eligibleRegion" + "eligibleTransactionVolume", "http://schema.org/eligibleTransactionVolume" + "email", "http://schema.org/email" + "embedUrl", "http://schema.org/embedUrl" + "embeddedTextCaption", "http://schema.org/embeddedTextCaption" + "emissionsCO2", "http://schema.org/emissionsCO2" + "employee", "http://schema.org/employee" + "employees", "http://schema.org/employees" + "employerOverview", "http://schema.org/employerOverview" + "employmentType", "http://schema.org/employmentType" + "employmentUnit", "http://schema.org/employmentUnit" + "encodesBioChemEntity", "http://schema.org/encodesBioChemEntity" + "encodesCreativeWork", "http://schema.org/encodesCreativeWork" + "encoding", "http://schema.org/encoding" + "encodingFormat", "http://schema.org/encodingFormat" + "encodingType", "http://schema.org/encodingType" + "encodings", "http://schema.org/encodings" + "endDate", "http://schema.org/endDate" + "endOffset", "http://schema.org/endOffset" + "endTime", "http://schema.org/endTime" + "endorsee", "http://schema.org/endorsee" + "endorsers", "http://schema.org/endorsers" + "energyEfficiencyScaleMax", "http://schema.org/energyEfficiencyScaleMax" + "energyEfficiencyScaleMin", "http://schema.org/energyEfficiencyScaleMin" + "engineDisplacement", "http://schema.org/engineDisplacement" + "enginePower", "http://schema.org/enginePower" + "engineType", "http://schema.org/engineType" + "entertainmentBusiness", "http://schema.org/entertainmentBusiness" + "epidemiology", "http://schema.org/epidemiology" + "episode", "http://schema.org/episode" + "episodeNumber", "http://schema.org/episodeNumber" + "episodes", "http://schema.org/episodes" + "equal", "http://schema.org/equal" + "error", "http://schema.org/error" + "estimatedCost", "http://schema.org/estimatedCost" + "estimatedFlightDuration", "http://schema.org/estimatedFlightDuration" + "estimatedSalary", "http://schema.org/estimatedSalary" + "estimatesRiskOf", "http://schema.org/estimatesRiskOf" + "ethicsPolicy", "http://schema.org/ethicsPolicy" + "event", "http://schema.org/event" + "eventAttendanceMode", "http://schema.org/eventAttendanceMode" + "eventSchedule", "http://schema.org/eventSchedule" + "eventStatus", "http://schema.org/eventStatus" + "events", "http://schema.org/events" + "evidenceLevel", "http://schema.org/evidenceLevel" + "evidenceOrigin", "http://schema.org/evidenceOrigin" + "exampleOfWork", "http://schema.org/exampleOfWork" + "exceptDate", "http://schema.org/exceptDate" + "exchangeRateSpread", "http://schema.org/exchangeRateSpread" + "executableLibraryName", "http://schema.org/executableLibraryName" + "exerciseCourse", "http://schema.org/exerciseCourse" + "exercisePlan", "http://schema.org/exercisePlan" + "exerciseRelatedDiet", "http://schema.org/exerciseRelatedDiet" + "exerciseType", "http://schema.org/exerciseType" + "exifData", "http://schema.org/exifData" + "expectedArrivalFrom", "http://schema.org/expectedArrivalFrom" + "expectedArrivalUntil", "http://schema.org/expectedArrivalUntil" + "expectedPrognosis", "http://schema.org/expectedPrognosis" + "expectsAcceptanceOf", "http://schema.org/expectsAcceptanceOf" + "experienceInPlaceOfEducation", "http://schema.org/experienceInPlaceOfEducation" + "experienceRequirements", "http://schema.org/experienceRequirements" + "expertConsiderations", "http://schema.org/expertConsiderations" + "expires", "http://schema.org/expires" + "expressedIn", "http://schema.org/expressedIn" + "familyName", "http://schema.org/familyName" + "fatContent", "http://schema.org/fatContent" + "faxNumber", "http://schema.org/faxNumber" + "featureList", "http://schema.org/featureList" + "feesAndCommissionsSpecification", "http://schema.org/feesAndCommissionsSpecification" + "fiberContent", "http://schema.org/fiberContent" + "fileFormat", "http://schema.org/fileFormat" + "fileSize", "http://schema.org/fileSize" + "financialAidEligible", "http://schema.org/financialAidEligible" + "firstAppearance", "http://schema.org/firstAppearance" + "firstPerformance", "http://schema.org/firstPerformance" + "flightDistance", "http://schema.org/flightDistance" + "flightNumber", "http://schema.org/flightNumber" + "floorLevel", "http://schema.org/floorLevel" + "floorLimit", "http://schema.org/floorLimit" + "floorSize", "http://schema.org/floorSize" + "followee", "http://schema.org/followee" + "follows", "http://schema.org/follows" + "followup", "http://schema.org/followup" + "foodEstablishment", "http://schema.org/foodEstablishment" + "foodEvent", "http://schema.org/foodEvent" + "foodWarning", "http://schema.org/foodWarning" + "founder", "http://schema.org/founder" + "founders", "http://schema.org/founders" + "foundingDate", "http://schema.org/foundingDate" + "foundingLocation", "http://schema.org/foundingLocation" + "free", "http://schema.org/free" + "freeShippingThreshold", "http://schema.org/freeShippingThreshold" + "frequency", "http://schema.org/frequency" + "fromLocation", "http://schema.org/fromLocation" + "fuelCapacity", "http://schema.org/fuelCapacity" + "fuelConsumption", "http://schema.org/fuelConsumption" + "fuelEfficiency", "http://schema.org/fuelEfficiency" + "fuelType", "http://schema.org/fuelType" + "functionalClass", "http://schema.org/functionalClass" + "fundedItem", "http://schema.org/fundedItem" + "funder", "http://schema.org/funder" + "funding", "http://schema.org/funding" + "game", "http://schema.org/game" + "gameAvailabilityType", "http://schema.org/gameAvailabilityType" + "gameEdition", "http://schema.org/gameEdition" + "gameItem", "http://schema.org/gameItem" + "gameLocation", "http://schema.org/gameLocation" + "gamePlatform", "http://schema.org/gamePlatform" + "gameServer", "http://schema.org/gameServer" + "gameTip", "http://schema.org/gameTip" + "gender", "http://schema.org/gender" + "genre", "http://schema.org/genre" + "geo", "http://schema.org/geo" + "geoContains", "http://schema.org/geoContains" + "geoCoveredBy", "http://schema.org/geoCoveredBy" + "geoCovers", "http://schema.org/geoCovers" + "geoCrosses", "http://schema.org/geoCrosses" + "geoDisjoint", "http://schema.org/geoDisjoint" + "geoEquals", "http://schema.org/geoEquals" + "geoIntersects", "http://schema.org/geoIntersects" + "geoMidpoint", "http://schema.org/geoMidpoint" + "geoOverlaps", "http://schema.org/geoOverlaps" + "geoRadius", "http://schema.org/geoRadius" + "geoTouches", "http://schema.org/geoTouches" + "geoWithin", "http://schema.org/geoWithin" + "geographicArea", "http://schema.org/geographicArea" + "gettingTestedInfo", "http://schema.org/gettingTestedInfo" + "givenName", "http://schema.org/givenName" + "globalLocationNumber", "http://schema.org/globalLocationNumber" + "governmentBenefitsInfo", "http://schema.org/governmentBenefitsInfo" + "gracePeriod", "http://schema.org/gracePeriod" + "grantee", "http://schema.org/grantee" + "greater", "http://schema.org/greater" + "greaterOrEqual", "http://schema.org/greaterOrEqual" + "gtin", "http://schema.org/gtin" + "gtin12", "http://schema.org/gtin12" + "gtin13", "http://schema.org/gtin13" + "gtin14", "http://schema.org/gtin14" + "gtin8", "http://schema.org/gtin8" + "guideline", "http://schema.org/guideline" + "guidelineDate", "http://schema.org/guidelineDate" + "guidelineSubject", "http://schema.org/guidelineSubject" + "handlingTime", "http://schema.org/handlingTime" + "hasAdultConsideration", "http://schema.org/hasAdultConsideration" + "hasBioChemEntityPart", "http://schema.org/hasBioChemEntityPart" + "hasBioPolymerSequence", "http://schema.org/hasBioPolymerSequence" + "hasBroadcastChannel", "http://schema.org/hasBroadcastChannel" + "hasCategoryCode", "http://schema.org/hasCategoryCode" + "hasCourse", "http://schema.org/hasCourse" + "hasCourseInstance", "http://schema.org/hasCourseInstance" + "hasCredential", "http://schema.org/hasCredential" + "hasDefinedTerm", "http://schema.org/hasDefinedTerm" + "hasDeliveryMethod", "http://schema.org/hasDeliveryMethod" + "hasDigitalDocumentPermission", "http://schema.org/hasDigitalDocumentPermission" + "hasDriveThroughService", "http://schema.org/hasDriveThroughService" + "hasEnergyConsumptionDetails", "http://schema.org/hasEnergyConsumptionDetails" + "hasEnergyEfficiencyCategory", "http://schema.org/hasEnergyEfficiencyCategory" + "hasHealthAspect", "http://schema.org/hasHealthAspect" + "hasMap", "http://schema.org/hasMap" + "hasMeasurement", "http://schema.org/hasMeasurement" + "hasMenu", "http://schema.org/hasMenu" + "hasMenuItem", "http://schema.org/hasMenuItem" + "hasMenuSection", "http://schema.org/hasMenuSection" + "hasMerchantReturnPolicy", "http://schema.org/hasMerchantReturnPolicy" + "hasMolecularFunction", "http://schema.org/hasMolecularFunction" + "hasOccupation", "http://schema.org/hasOccupation" + "hasOfferCatalog", "http://schema.org/hasOfferCatalog" + "hasPOS", "http://schema.org/hasPOS" + "hasPart", "http://schema.org/hasPart" + "hasProductReturnPolicy", "http://schema.org/hasProductReturnPolicy" + "hasRepresentation", "http://schema.org/hasRepresentation" + "hasVariant", "http://schema.org/hasVariant" + "headline", "http://schema.org/headline" + "healthCondition", "http://schema.org/healthCondition" + "healthPlanCoinsuranceOption", "http://schema.org/healthPlanCoinsuranceOption" + "healthPlanCoinsuranceRate", "http://schema.org/healthPlanCoinsuranceRate" + "healthPlanCopay", "http://schema.org/healthPlanCopay" + "healthPlanCopayOption", "http://schema.org/healthPlanCopayOption" + "healthPlanCostSharing", "http://schema.org/healthPlanCostSharing" + "healthPlanDrugOption", "http://schema.org/healthPlanDrugOption" + "healthPlanDrugTier", "http://schema.org/healthPlanDrugTier" + "healthPlanId", "http://schema.org/healthPlanId" + "healthPlanMarketingUrl", "http://schema.org/healthPlanMarketingUrl" + "healthPlanNetworkId", "http://schema.org/healthPlanNetworkId" + "healthPlanNetworkTier", "http://schema.org/healthPlanNetworkTier" + "healthPlanPharmacyCategory", "http://schema.org/healthPlanPharmacyCategory" + "healthcareReportingData", "http://schema.org/healthcareReportingData" + "height", "http://schema.org/height" + "highPrice", "http://schema.org/highPrice" + "hiringOrganization", "http://schema.org/hiringOrganization" + "holdingArchive", "http://schema.org/holdingArchive" + "homeLocation", "http://schema.org/homeLocation" + "homeTeam", "http://schema.org/homeTeam" + "honorificPrefix", "http://schema.org/honorificPrefix" + "honorificSuffix", "http://schema.org/honorificSuffix" + "hospitalAffiliation", "http://schema.org/hospitalAffiliation" + "hostingOrganization", "http://schema.org/hostingOrganization" + "hoursAvailable", "http://schema.org/hoursAvailable" + "howPerformed", "http://schema.org/howPerformed" + "httpMethod", "http://schema.org/httpMethod" + "iataCode", "http://schema.org/iataCode" + "icaoCode", "http://schema.org/icaoCode" + "identifier", "http://schema.org/identifier" + "identifyingExam", "http://schema.org/identifyingExam" + "identifyingTest", "http://schema.org/identifyingTest" + "illustrator", "http://schema.org/illustrator" + "image", "http://schema.org/image" + "imagingTechnique", "http://schema.org/imagingTechnique" + "inAlbum", "http://schema.org/inAlbum" + "inBroadcastLineup", "http://schema.org/inBroadcastLineup" + "inChI", "http://schema.org/inChI" + "inChIKey", "http://schema.org/inChIKey" + "inCodeSet", "http://schema.org/inCodeSet" + "inDefinedTermSet", "http://schema.org/inDefinedTermSet" + "inLanguage", "http://schema.org/inLanguage" + "inPlaylist", "http://schema.org/inPlaylist" + "inProductGroupWithID", "http://schema.org/inProductGroupWithID" + "inStoreReturnsOffered", "http://schema.org/inStoreReturnsOffered" + "inSupportOf", "http://schema.org/inSupportOf" + "incentiveCompensation", "http://schema.org/incentiveCompensation" + "incentives", "http://schema.org/incentives" + "includedComposition", "http://schema.org/includedComposition" + "includedDataCatalog", "http://schema.org/includedDataCatalog" + "includedInDataCatalog", "http://schema.org/includedInDataCatalog" + "includedInHealthInsurancePlan", "http://schema.org/includedInHealthInsurancePlan" + "includedRiskFactor", "http://schema.org/includedRiskFactor" + "includesAttraction", "http://schema.org/includesAttraction" + "includesHealthPlanFormulary", "http://schema.org/includesHealthPlanFormulary" + "includesHealthPlanNetwork", "http://schema.org/includesHealthPlanNetwork" + "includesObject", "http://schema.org/includesObject" + "increasesRiskOf", "http://schema.org/increasesRiskOf" + "industry", "http://schema.org/industry" + "ineligibleRegion", "http://schema.org/ineligibleRegion" + "infectiousAgent", "http://schema.org/infectiousAgent" + "infectiousAgentClass", "http://schema.org/infectiousAgentClass" + "ingredients", "http://schema.org/ingredients" + "inker", "http://schema.org/inker" + "insertion", "http://schema.org/insertion" + "installUrl", "http://schema.org/installUrl" + "instructor", "http://schema.org/instructor" + "instrument", "http://schema.org/instrument" + "intensity", "http://schema.org/intensity" + "interactingDrug", "http://schema.org/interactingDrug" + "interactionCount", "http://schema.org/interactionCount" + "interactionService", "http://schema.org/interactionService" + "interactionStatistic", "http://schema.org/interactionStatistic" + "interactionType", "http://schema.org/interactionType" + "interactivityType", "http://schema.org/interactivityType" + "interestRate", "http://schema.org/interestRate" + "interpretedAsClaim", "http://schema.org/interpretedAsClaim" + "inventoryLevel", "http://schema.org/inventoryLevel" + "inverseOf", "http://schema.org/inverseOf" + "isAcceptingNewPatients", "http://schema.org/isAcceptingNewPatients" + "isAccessibleForFree", "http://schema.org/isAccessibleForFree" + "isAccessoryOrSparePartFor", "http://schema.org/isAccessoryOrSparePartFor" + "isAvailableGenerically", "http://schema.org/isAvailableGenerically" + "isBasedOn", "http://schema.org/isBasedOn" + "isBasedOnUrl", "http://schema.org/isBasedOnUrl" + "isConsumableFor", "http://schema.org/isConsumableFor" + "isEncodedByBioChemEntity", "http://schema.org/isEncodedByBioChemEntity" + "isFamilyFriendly", "http://schema.org/isFamilyFriendly" + "isGift", "http://schema.org/isGift" + "isInvolvedInBiologicalProcess", "http://schema.org/isInvolvedInBiologicalProcess" + "isLiveBroadcast", "http://schema.org/isLiveBroadcast" + "isLocatedInSubcellularLocation", "http://schema.org/isLocatedInSubcellularLocation" + "isPartOf", "http://schema.org/isPartOf" + "isPartOfBioChemEntity", "http://schema.org/isPartOfBioChemEntity" + "isPlanForApartment", "http://schema.org/isPlanForApartment" + "isProprietary", "http://schema.org/isProprietary" + "isRelatedTo", "http://schema.org/isRelatedTo" + "isResizable", "http://schema.org/isResizable" + "isSimilarTo", "http://schema.org/isSimilarTo" + "isUnlabelledFallback", "http://schema.org/isUnlabelledFallback" + "isVariantOf", "http://schema.org/isVariantOf" + "isbn", "http://schema.org/isbn" + "isicV4", "http://schema.org/isicV4" + "iso6523Code", "http://schema.org/iso6523Code" + "isrcCode", "http://schema.org/isrcCode" + "issn", "http://schema.org/issn" + "issueNumber", "http://schema.org/issueNumber" + "issuedBy", "http://schema.org/issuedBy" + "issuedThrough", "http://schema.org/issuedThrough" + "iswcCode", "http://schema.org/iswcCode" + "item", "http://schema.org/item" + "itemCondition", "http://schema.org/itemCondition" + "itemDefectReturnFees", "http://schema.org/itemDefectReturnFees" + "itemDefectReturnLabelSource", "http://schema.org/itemDefectReturnLabelSource" + "itemDefectReturnShippingFeesAmount", "http://schema.org/itemDefectReturnShippingFeesAmount" + "itemListElement", "http://schema.org/itemListElement" + "itemListOrder", "http://schema.org/itemListOrder" + "itemLocation", "http://schema.org/itemLocation" + "itemOffered", "http://schema.org/itemOffered" + "itemReviewed", "http://schema.org/itemReviewed" + "itemShipped", "http://schema.org/itemShipped" + "itinerary", "http://schema.org/itinerary" + "iupacName", "http://schema.org/iupacName" + "jobBenefits", "http://schema.org/jobBenefits" + "jobImmediateStart", "http://schema.org/jobImmediateStart" + "jobLocation", "http://schema.org/jobLocation" + "jobLocationType", "http://schema.org/jobLocationType" + "jobStartDate", "http://schema.org/jobStartDate" + "jobTitle", "http://schema.org/jobTitle" + "jurisdiction", "http://schema.org/jurisdiction" + "keywords", "http://schema.org/keywords" + "knownVehicleDamages", "http://schema.org/knownVehicleDamages" + "knows", "http://schema.org/knows" + "knowsAbout", "http://schema.org/knowsAbout" + "knowsLanguage", "http://schema.org/knowsLanguage" + "labelDetails", "http://schema.org/labelDetails" + "landlord", "http://schema.org/landlord" + "language", "http://schema.org/language" + "lastReviewed", "http://schema.org/lastReviewed" + "latitude", "http://schema.org/latitude" + "layoutImage", "http://schema.org/layoutImage" + "learningResourceType", "http://schema.org/learningResourceType" + "leaseLength", "http://schema.org/leaseLength" + "legalName", "http://schema.org/legalName" + "legalStatus", "http://schema.org/legalStatus" + "legislationApplies", "http://schema.org/legislationApplies" + "legislationChanges", "http://schema.org/legislationChanges" + "legislationConsolidates", "http://schema.org/legislationConsolidates" + "legislationDate", "http://schema.org/legislationDate" + "legislationDateVersion", "http://schema.org/legislationDateVersion" + "legislationIdentifier", "http://schema.org/legislationIdentifier" + "legislationJurisdiction", "http://schema.org/legislationJurisdiction" + "legislationLegalForce", "http://schema.org/legislationLegalForce" + "legislationLegalValue", "http://schema.org/legislationLegalValue" + "legislationPassedBy", "http://schema.org/legislationPassedBy" + "legislationResponsible", "http://schema.org/legislationResponsible" + "legislationTransposes", "http://schema.org/legislationTransposes" + "legislationType", "http://schema.org/legislationType" + "leiCode", "http://schema.org/leiCode" + "lender", "http://schema.org/lender" + "lesser", "http://schema.org/lesser" + "lesserOrEqual", "http://schema.org/lesserOrEqual" + "letterer", "http://schema.org/letterer" + "license", "http://schema.org/license" + "line", "http://schema.org/line" + "linkRelationship", "http://schema.org/linkRelationship" + "liveBlogUpdate", "http://schema.org/liveBlogUpdate" + "loanMortgageMandateAmount", "http://schema.org/loanMortgageMandateAmount" + "loanPaymentAmount", "http://schema.org/loanPaymentAmount" + "loanPaymentFrequency", "http://schema.org/loanPaymentFrequency" + "loanRepaymentForm", "http://schema.org/loanRepaymentForm" + "loanTerm", "http://schema.org/loanTerm" + "loanType", "http://schema.org/loanType" + "location", "http://schema.org/location" + "locationCreated", "http://schema.org/locationCreated" + "lodgingUnitDescription", "http://schema.org/lodgingUnitDescription" + "lodgingUnitType", "http://schema.org/lodgingUnitType" + "logo", "http://schema.org/logo" + "longitude", "http://schema.org/longitude" + "loser", "http://schema.org/loser" + "lowPrice", "http://schema.org/lowPrice" + "lyricist", "http://schema.org/lyricist" + "lyrics", "http://schema.org/lyrics" + "mainContentOfPage", "http://schema.org/mainContentOfPage" + "mainEntity", "http://schema.org/mainEntity" + "mainEntityOfPage", "http://schema.org/mainEntityOfPage" + "maintainer", "http://schema.org/maintainer" + "makesOffer", "http://schema.org/makesOffer" + "manufacturer", "http://schema.org/manufacturer" + "map", "http://schema.org/map" + "mapType", "http://schema.org/mapType" + "maps", "http://schema.org/maps" + "marginOfError", "http://schema.org/marginOfError" + "masthead", "http://schema.org/masthead" + "material", "http://schema.org/material" + "materialExtent", "http://schema.org/materialExtent" + "mathExpression", "http://schema.org/mathExpression" + "maxPrice", "http://schema.org/maxPrice" + "maxValue", "http://schema.org/maxValue" + "maximumAttendeeCapacity", "http://schema.org/maximumAttendeeCapacity" + "maximumEnrollment", "http://schema.org/maximumEnrollment" + "maximumIntake", "http://schema.org/maximumIntake" + "maximumPhysicalAttendeeCapacity", "http://schema.org/maximumPhysicalAttendeeCapacity" + "maximumVirtualAttendeeCapacity", "http://schema.org/maximumVirtualAttendeeCapacity" + "mealService", "http://schema.org/mealService" + "measuredProperty", "http://schema.org/measuredProperty" + "measurementDenominator", "http://schema.org/measurementDenominator" + "measurementMethod", "http://schema.org/measurementMethod" + "measurementQualifier", "http://schema.org/measurementQualifier" + "measurementTechnique", "http://schema.org/measurementTechnique" + "mechanismOfAction", "http://schema.org/mechanismOfAction" + "mediaAuthenticityCategory", "http://schema.org/mediaAuthenticityCategory" + "mediaItemAppearance", "http://schema.org/mediaItemAppearance" + "median", "http://schema.org/median" + "medicalAudience", "http://schema.org/medicalAudience" + "medicalSpecialty", "http://schema.org/medicalSpecialty" + "medicineSystem", "http://schema.org/medicineSystem" + "meetsEmissionStandard", "http://schema.org/meetsEmissionStandard" + "member", "http://schema.org/member" + "memberOf", "http://schema.org/memberOf" + "members", "http://schema.org/members" + "membershipNumber", "http://schema.org/membershipNumber" + "membershipPointsEarned", "http://schema.org/membershipPointsEarned" + "memoryRequirements", "http://schema.org/memoryRequirements" + "mentions", "http://schema.org/mentions" + "menu", "http://schema.org/menu" + "menuAddOn", "http://schema.org/menuAddOn" + "merchant", "http://schema.org/merchant" + "merchantReturnDays", "http://schema.org/merchantReturnDays" + "merchantReturnLink", "http://schema.org/merchantReturnLink" + "messageAttachment", "http://schema.org/messageAttachment" + "mileageFromOdometer", "http://schema.org/mileageFromOdometer" + "minPrice", "http://schema.org/minPrice" + "minValue", "http://schema.org/minValue" + "minimumPaymentDue", "http://schema.org/minimumPaymentDue" + "missionCoveragePrioritiesPolicy", "http://schema.org/missionCoveragePrioritiesPolicy" + "mobileUrl", "http://schema.org/mobileUrl" + "model", "http://schema.org/model" + "modelDate", "http://schema.org/modelDate" + "modifiedTime", "http://schema.org/modifiedTime" + "molecularFormula", "http://schema.org/molecularFormula" + "molecularWeight", "http://schema.org/molecularWeight" + "monoisotopicMolecularWeight", "http://schema.org/monoisotopicMolecularWeight" + "monthlyMinimumRepaymentAmount", "http://schema.org/monthlyMinimumRepaymentAmount" + "monthsOfExperience", "http://schema.org/monthsOfExperience" + "mpn", "http://schema.org/mpn" + "multipleValues", "http://schema.org/multipleValues" + "muscleAction", "http://schema.org/muscleAction" + "musicArrangement", "http://schema.org/musicArrangement" + "musicBy", "http://schema.org/musicBy" + "musicCompositionForm", "http://schema.org/musicCompositionForm" + "musicGroupMember", "http://schema.org/musicGroupMember" + "musicReleaseFormat", "http://schema.org/musicReleaseFormat" + "musicalKey", "http://schema.org/musicalKey" + "naics", "http://schema.org/naics" + "name", "http://schema.org/name" + "namedPosition", "http://schema.org/namedPosition" + "nationality", "http://schema.org/nationality" + "naturalProgression", "http://schema.org/naturalProgression" + "negativeNotes", "http://schema.org/negativeNotes" + "nerve", "http://schema.org/nerve" + "nerveMotor", "http://schema.org/nerveMotor" + "netWorth", "http://schema.org/netWorth" + "newsUpdatesAndGuidelines", "http://schema.org/newsUpdatesAndGuidelines" + "nextItem", "http://schema.org/nextItem" + "noBylinesPolicy", "http://schema.org/noBylinesPolicy" + "nonEqual", "http://schema.org/nonEqual" + "nonProprietaryName", "http://schema.org/nonProprietaryName" + "nonprofitStatus", "http://schema.org/nonprofitStatus" + "normalRange", "http://schema.org/normalRange" + "nsn", "http://schema.org/nsn" + "numAdults", "http://schema.org/numAdults" + "numChildren", "http://schema.org/numChildren" + "numConstraints", "http://schema.org/numConstraints" + "numTracks", "http://schema.org/numTracks" + "numberOfAccommodationUnits", "http://schema.org/numberOfAccommodationUnits" + "numberOfAirbags", "http://schema.org/numberOfAirbags" + "numberOfAvailableAccommodationUnits", "http://schema.org/numberOfAvailableAccommodationUnits" + "numberOfAxles", "http://schema.org/numberOfAxles" + "numberOfBathroomsTotal", "http://schema.org/numberOfBathroomsTotal" + "numberOfBedrooms", "http://schema.org/numberOfBedrooms" + "numberOfBeds", "http://schema.org/numberOfBeds" + "numberOfCredits", "http://schema.org/numberOfCredits" + "numberOfDoors", "http://schema.org/numberOfDoors" + "numberOfEmployees", "http://schema.org/numberOfEmployees" + "numberOfEpisodes", "http://schema.org/numberOfEpisodes" + "numberOfForwardGears", "http://schema.org/numberOfForwardGears" + "numberOfFullBathrooms", "http://schema.org/numberOfFullBathrooms" + "numberOfItems", "http://schema.org/numberOfItems" + "numberOfLoanPayments", "http://schema.org/numberOfLoanPayments" + "numberOfPages", "http://schema.org/numberOfPages" + "numberOfPartialBathrooms", "http://schema.org/numberOfPartialBathrooms" + "numberOfPlayers", "http://schema.org/numberOfPlayers" + "numberOfPreviousOwners", "http://schema.org/numberOfPreviousOwners" + "numberOfRooms", "http://schema.org/numberOfRooms" + "numberOfSeasons", "http://schema.org/numberOfSeasons" + "numberedPosition", "http://schema.org/numberedPosition" + "nutrition", "http://schema.org/nutrition" + "object", "http://schema.org/object" + "observationAbout", "http://schema.org/observationAbout" + "observationDate", "http://schema.org/observationDate" + "observationPeriod", "http://schema.org/observationPeriod" + "occupancy", "http://schema.org/occupancy" + "occupationLocation", "http://schema.org/occupationLocation" + "occupationalCategory", "http://schema.org/occupationalCategory" + "occupationalCredentialAwarded", "http://schema.org/occupationalCredentialAwarded" + "offerCount", "http://schema.org/offerCount" + "offeredBy", "http://schema.org/offeredBy" + "offers", "http://schema.org/offers" + "offersPrescriptionByMail", "http://schema.org/offersPrescriptionByMail" + "openingHours", "http://schema.org/openingHours" + "openingHoursSpecification", "http://schema.org/openingHoursSpecification" + "opens", "http://schema.org/opens" + "operatingSystem", "http://schema.org/operatingSystem" + "opponent", "http://schema.org/opponent" + "option", "http://schema.org/option" + "orderDate", "http://schema.org/orderDate" + "orderDelivery", "http://schema.org/orderDelivery" + "orderItemNumber", "http://schema.org/orderItemNumber" + "orderItemStatus", "http://schema.org/orderItemStatus" + "orderNumber", "http://schema.org/orderNumber" + "orderQuantity", "http://schema.org/orderQuantity" + "orderStatus", "http://schema.org/orderStatus" + "orderedItem", "http://schema.org/orderedItem" + "organizer", "http://schema.org/organizer" + "originAddress", "http://schema.org/originAddress" + "originalMediaContextDescription", "http://schema.org/originalMediaContextDescription" + "originalMediaLink", "http://schema.org/originalMediaLink" + "originatesFrom", "http://schema.org/originatesFrom" + "overdosage", "http://schema.org/overdosage" + "ownedFrom", "http://schema.org/ownedFrom" + "ownedThrough", "http://schema.org/ownedThrough" + "ownershipFundingInfo", "http://schema.org/ownershipFundingInfo" + "owns", "http://schema.org/owns" + "pageEnd", "http://schema.org/pageEnd" + "pageStart", "http://schema.org/pageStart" + "pagination", "http://schema.org/pagination" + "parent", "http://schema.org/parent" + "parentItem", "http://schema.org/parentItem" + "parentOrganization", "http://schema.org/parentOrganization" + "parentService", "http://schema.org/parentService" + "parentTaxon", "http://schema.org/parentTaxon" + "parents", "http://schema.org/parents" + "partOfEpisode", "http://schema.org/partOfEpisode" + "partOfInvoice", "http://schema.org/partOfInvoice" + "partOfOrder", "http://schema.org/partOfOrder" + "partOfSeason", "http://schema.org/partOfSeason" + "partOfSeries", "http://schema.org/partOfSeries" + "partOfSystem", "http://schema.org/partOfSystem" + "partOfTVSeries", "http://schema.org/partOfTVSeries" + "partOfTrip", "http://schema.org/partOfTrip" + "participant", "http://schema.org/participant" + "partySize", "http://schema.org/partySize" + "passengerPriorityStatus", "http://schema.org/passengerPriorityStatus" + "passengerSequenceNumber", "http://schema.org/passengerSequenceNumber" + "pathophysiology", "http://schema.org/pathophysiology" + "pattern", "http://schema.org/pattern" + "payload", "http://schema.org/payload" + "paymentAccepted", "http://schema.org/paymentAccepted" + "paymentDue", "http://schema.org/paymentDue" + "paymentDueDate", "http://schema.org/paymentDueDate" + "paymentMethod", "http://schema.org/paymentMethod" + "paymentMethodId", "http://schema.org/paymentMethodId" + "paymentStatus", "http://schema.org/paymentStatus" + "paymentUrl", "http://schema.org/paymentUrl" + "penciler", "http://schema.org/penciler" + "percentile10", "http://schema.org/percentile10" + "percentile25", "http://schema.org/percentile25" + "percentile75", "http://schema.org/percentile75" + "percentile90", "http://schema.org/percentile90" + "performTime", "http://schema.org/performTime" + "performer", "http://schema.org/performer" + "performerIn", "http://schema.org/performerIn" + "performers", "http://schema.org/performers" + "permissionType", "http://schema.org/permissionType" + "permissions", "http://schema.org/permissions" + "permitAudience", "http://schema.org/permitAudience" + "permittedUsage", "http://schema.org/permittedUsage" + "petsAllowed", "http://schema.org/petsAllowed" + "phoneticText", "http://schema.org/phoneticText" + "photo", "http://schema.org/photo" + "photos", "http://schema.org/photos" + "physicalRequirement", "http://schema.org/physicalRequirement" + "physiologicalBenefits", "http://schema.org/physiologicalBenefits" + "pickupLocation", "http://schema.org/pickupLocation" + "pickupTime", "http://schema.org/pickupTime" + "playMode", "http://schema.org/playMode" + "playerType", "http://schema.org/playerType" + "playersOnline", "http://schema.org/playersOnline" + "polygon", "http://schema.org/polygon" + "populationType", "http://schema.org/populationType" + "position", "http://schema.org/position" + "positiveNotes", "http://schema.org/positiveNotes" + "possibleComplication", "http://schema.org/possibleComplication" + "possibleTreatment", "http://schema.org/possibleTreatment" + "postOfficeBoxNumber", "http://schema.org/postOfficeBoxNumber" + "postOp", "http://schema.org/postOp" + "postalCode", "http://schema.org/postalCode" + "postalCodeBegin", "http://schema.org/postalCodeBegin" + "postalCodeEnd", "http://schema.org/postalCodeEnd" + "postalCodePrefix", "http://schema.org/postalCodePrefix" + "postalCodeRange", "http://schema.org/postalCodeRange" + "potentialAction", "http://schema.org/potentialAction" + "potentialUse", "http://schema.org/potentialUse" + "preOp", "http://schema.org/preOp" + "predecessorOf", "http://schema.org/predecessorOf" + "pregnancyCategory", "http://schema.org/pregnancyCategory" + "pregnancyWarning", "http://schema.org/pregnancyWarning" + "prepTime", "http://schema.org/prepTime" + "preparation", "http://schema.org/preparation" + "prescribingInfo", "http://schema.org/prescribingInfo" + "prescriptionStatus", "http://schema.org/prescriptionStatus" + "previousItem", "http://schema.org/previousItem" + "previousStartDate", "http://schema.org/previousStartDate" + "price", "http://schema.org/price" + "priceComponent", "http://schema.org/priceComponent" + "priceComponentType", "http://schema.org/priceComponentType" + "priceCurrency", "http://schema.org/priceCurrency" + "priceRange", "http://schema.org/priceRange" + "priceSpecification", "http://schema.org/priceSpecification" + "priceType", "http://schema.org/priceType" + "priceValidUntil", "http://schema.org/priceValidUntil" + "primaryImageOfPage", "http://schema.org/primaryImageOfPage" + "primaryPrevention", "http://schema.org/primaryPrevention" + "printColumn", "http://schema.org/printColumn" + "printEdition", "http://schema.org/printEdition" + "printPage", "http://schema.org/printPage" + "printSection", "http://schema.org/printSection" + "procedure", "http://schema.org/procedure" + "procedureType", "http://schema.org/procedureType" + "processingTime", "http://schema.org/processingTime" + "processorRequirements", "http://schema.org/processorRequirements" + "producer", "http://schema.org/producer" + "produces", "http://schema.org/produces" + "productGroupID", "http://schema.org/productGroupID" + "productID", "http://schema.org/productID" + "productReturnDays", "http://schema.org/productReturnDays" + "productReturnLink", "http://schema.org/productReturnLink" + "productSupported", "http://schema.org/productSupported" + "productionCompany", "http://schema.org/productionCompany" + "productionDate", "http://schema.org/productionDate" + "proficiencyLevel", "http://schema.org/proficiencyLevel" + "programMembershipUsed", "http://schema.org/programMembershipUsed" + "programName", "http://schema.org/programName" + "programPrerequisites", "http://schema.org/programPrerequisites" + "programType", "http://schema.org/programType" + "programmingLanguage", "http://schema.org/programmingLanguage" + "programmingModel", "http://schema.org/programmingModel" + "propertyID", "http://schema.org/propertyID" + "proprietaryName", "http://schema.org/proprietaryName" + "proteinContent", "http://schema.org/proteinContent" + "provider", "http://schema.org/provider" + "providerMobility", "http://schema.org/providerMobility" + "providesBroadcastService", "http://schema.org/providesBroadcastService" + "providesService", "http://schema.org/providesService" + "publicAccess", "http://schema.org/publicAccess" + "publicTransportClosuresInfo", "http://schema.org/publicTransportClosuresInfo" + "publication", "http://schema.org/publication" + "publicationType", "http://schema.org/publicationType" + "publishedBy", "http://schema.org/publishedBy" + "publishedOn", "http://schema.org/publishedOn" + "publisher", "http://schema.org/publisher" + "publisherImprint", "http://schema.org/publisherImprint" + "publishingPrinciples", "http://schema.org/publishingPrinciples" + "purchaseDate", "http://schema.org/purchaseDate" + "qualifications", "http://schema.org/qualifications" + "quarantineGuidelines", "http://schema.org/quarantineGuidelines" + "query", "http://schema.org/query" + "quest", "http://schema.org/quest" + "question", "http://schema.org/question" + "rangeIncludes", "http://schema.org/rangeIncludes" + "ratingCount", "http://schema.org/ratingCount" + "ratingExplanation", "http://schema.org/ratingExplanation" + "ratingValue", "http://schema.org/ratingValue" + "readBy", "http://schema.org/readBy" + "readonlyValue", "http://schema.org/readonlyValue" + "realEstateAgent", "http://schema.org/realEstateAgent" + "recipe", "http://schema.org/recipe" + "recipeCategory", "http://schema.org/recipeCategory" + "recipeCuisine", "http://schema.org/recipeCuisine" + "recipeIngredient", "http://schema.org/recipeIngredient" + "recipeInstructions", "http://schema.org/recipeInstructions" + "recipeYield", "http://schema.org/recipeYield" + "recipient", "http://schema.org/recipient" + "recognizedBy", "http://schema.org/recognizedBy" + "recognizingAuthority", "http://schema.org/recognizingAuthority" + "recommendationStrength", "http://schema.org/recommendationStrength" + "recommendedIntake", "http://schema.org/recommendedIntake" + "recordLabel", "http://schema.org/recordLabel" + "recordedAs", "http://schema.org/recordedAs" + "recordedAt", "http://schema.org/recordedAt" + "recordedIn", "http://schema.org/recordedIn" + "recordingOf", "http://schema.org/recordingOf" + "recourseLoan", "http://schema.org/recourseLoan" + "referenceQuantity", "http://schema.org/referenceQuantity" + "referencesOrder", "http://schema.org/referencesOrder" + "refundType", "http://schema.org/refundType" + "regionDrained", "http://schema.org/regionDrained" + "regionsAllowed", "http://schema.org/regionsAllowed" + "relatedAnatomy", "http://schema.org/relatedAnatomy" + "relatedCondition", "http://schema.org/relatedCondition" + "relatedDrug", "http://schema.org/relatedDrug" + "relatedLink", "http://schema.org/relatedLink" + "relatedStructure", "http://schema.org/relatedStructure" + "relatedTherapy", "http://schema.org/relatedTherapy" + "relatedTo", "http://schema.org/relatedTo" + "releaseDate", "http://schema.org/releaseDate" + "releaseNotes", "http://schema.org/releaseNotes" + "releaseOf", "http://schema.org/releaseOf" + "releasedEvent", "http://schema.org/releasedEvent" + "relevantOccupation", "http://schema.org/relevantOccupation" + "relevantSpecialty", "http://schema.org/relevantSpecialty" + "remainingAttendeeCapacity", "http://schema.org/remainingAttendeeCapacity" + "renegotiableLoan", "http://schema.org/renegotiableLoan" + "repeatCount", "http://schema.org/repeatCount" + "repeatFrequency", "http://schema.org/repeatFrequency" + "repetitions", "http://schema.org/repetitions" + "replacee", "http://schema.org/replacee" + "replacer", "http://schema.org/replacer" + "replyToUrl", "http://schema.org/replyToUrl" + "reportNumber", "http://schema.org/reportNumber" + "representativeOfPage", "http://schema.org/representativeOfPage" + "requiredCollateral", "http://schema.org/requiredCollateral" + "requiredGender", "http://schema.org/requiredGender" + "requiredMaxAge", "http://schema.org/requiredMaxAge" + "requiredMinAge", "http://schema.org/requiredMinAge" + "requiredQuantity", "http://schema.org/requiredQuantity" + "requirements", "http://schema.org/requirements" + "requiresSubscription", "http://schema.org/requiresSubscription" + "reservationFor", "http://schema.org/reservationFor" + "reservationId", "http://schema.org/reservationId" + "reservationStatus", "http://schema.org/reservationStatus" + "reservedTicket", "http://schema.org/reservedTicket" + "responsibilities", "http://schema.org/responsibilities" + "restPeriods", "http://schema.org/restPeriods" + "restockingFee", "http://schema.org/restockingFee" + "result", "http://schema.org/result" + "resultComment", "http://schema.org/resultComment" + "resultReview", "http://schema.org/resultReview" + "returnFees", "http://schema.org/returnFees" + "returnLabelSource", "http://schema.org/returnLabelSource" + "returnMethod", "http://schema.org/returnMethod" + "returnPolicyCategory", "http://schema.org/returnPolicyCategory" + "returnPolicyCountry", "http://schema.org/returnPolicyCountry" + "returnPolicySeasonalOverride", "http://schema.org/returnPolicySeasonalOverride" + "returnShippingFeesAmount", "http://schema.org/returnShippingFeesAmount" + "review", "http://schema.org/review" + "reviewAspect", "http://schema.org/reviewAspect" + "reviewBody", "http://schema.org/reviewBody" + "reviewCount", "http://schema.org/reviewCount" + "reviewRating", "http://schema.org/reviewRating" + "reviewedBy", "http://schema.org/reviewedBy" + "reviews", "http://schema.org/reviews" + "riskFactor", "http://schema.org/riskFactor" + "risks", "http://schema.org/risks" + "roleName", "http://schema.org/roleName" + "roofLoad", "http://schema.org/roofLoad" + "rsvpResponse", "http://schema.org/rsvpResponse" + "runsTo", "http://schema.org/runsTo" + "runtime", "http://schema.org/runtime" + "runtimePlatform", "http://schema.org/runtimePlatform" + "rxcui", "http://schema.org/rxcui" + "safetyConsideration", "http://schema.org/safetyConsideration" + "salaryCurrency", "http://schema.org/salaryCurrency" + "salaryUponCompletion", "http://schema.org/salaryUponCompletion" + "sameAs", "http://schema.org/sameAs" + "sampleType", "http://schema.org/sampleType" + "saturatedFatContent", "http://schema.org/saturatedFatContent" + "scheduleTimezone", "http://schema.org/scheduleTimezone" + "scheduledPaymentDate", "http://schema.org/scheduledPaymentDate" + "scheduledTime", "http://schema.org/scheduledTime" + "schemaVersion", "http://schema.org/schemaVersion" + "schoolClosuresInfo", "http://schema.org/schoolClosuresInfo" + "screenCount", "http://schema.org/screenCount" + "screenshot", "http://schema.org/screenshot" + "sdDatePublished", "http://schema.org/sdDatePublished" + "sdLicense", "http://schema.org/sdLicense" + "sdPublisher", "http://schema.org/sdPublisher" + "season", "http://schema.org/season" + "seasonNumber", "http://schema.org/seasonNumber" + "seasons", "http://schema.org/seasons" + "seatNumber", "http://schema.org/seatNumber" + "seatRow", "http://schema.org/seatRow" + "seatSection", "http://schema.org/seatSection" + "seatingCapacity", "http://schema.org/seatingCapacity" + "seatingType", "http://schema.org/seatingType" + "secondaryPrevention", "http://schema.org/secondaryPrevention" + "securityClearanceRequirement", "http://schema.org/securityClearanceRequirement" + "securityScreening", "http://schema.org/securityScreening" + "seeks", "http://schema.org/seeks" + "seller", "http://schema.org/seller" + "sender", "http://schema.org/sender" + "sensoryRequirement", "http://schema.org/sensoryRequirement" + "sensoryUnit", "http://schema.org/sensoryUnit" + "serialNumber", "http://schema.org/serialNumber" + "seriousAdverseOutcome", "http://schema.org/seriousAdverseOutcome" + "serverStatus", "http://schema.org/serverStatus" + "servesCuisine", "http://schema.org/servesCuisine" + "serviceArea", "http://schema.org/serviceArea" + "serviceAudience", "http://schema.org/serviceAudience" + "serviceLocation", "http://schema.org/serviceLocation" + "serviceOperator", "http://schema.org/serviceOperator" + "serviceOutput", "http://schema.org/serviceOutput" + "servicePhone", "http://schema.org/servicePhone" + "servicePostalAddress", "http://schema.org/servicePostalAddress" + "serviceSmsNumber", "http://schema.org/serviceSmsNumber" + "serviceType", "http://schema.org/serviceType" + "serviceUrl", "http://schema.org/serviceUrl" + "servingSize", "http://schema.org/servingSize" + "sha256", "http://schema.org/sha256" + "sharedContent", "http://schema.org/sharedContent" + "shippingDestination", "http://schema.org/shippingDestination" + "shippingDetails", "http://schema.org/shippingDetails" + "shippingLabel", "http://schema.org/shippingLabel" + "shippingOrigin", "http://schema.org/shippingOrigin" + "shippingRate", "http://schema.org/shippingRate" + "shippingSettingsLink", "http://schema.org/shippingSettingsLink" + "sibling", "http://schema.org/sibling" + "siblings", "http://schema.org/siblings" + "signDetected", "http://schema.org/signDetected" + "signOrSymptom", "http://schema.org/signOrSymptom" + "significance", "http://schema.org/significance" + "significantLink", "http://schema.org/significantLink" + "significantLinks", "http://schema.org/significantLinks" + "size", "http://schema.org/size" + "sizeGroup", "http://schema.org/sizeGroup" + "sizeSystem", "http://schema.org/sizeSystem" + "skills", "http://schema.org/skills" + "sku", "http://schema.org/sku" + "slogan", "http://schema.org/slogan" + "smiles", "http://schema.org/smiles" + "smokingAllowed", "http://schema.org/smokingAllowed" + "sodiumContent", "http://schema.org/sodiumContent" + "softwareAddOn", "http://schema.org/softwareAddOn" + "softwareHelp", "http://schema.org/softwareHelp" + "softwareRequirements", "http://schema.org/softwareRequirements" + "softwareVersion", "http://schema.org/softwareVersion" + "sourceOrganization", "http://schema.org/sourceOrganization" + "sourcedFrom", "http://schema.org/sourcedFrom" + "spatial", "http://schema.org/spatial" + "spatialCoverage", "http://schema.org/spatialCoverage" + "speakable", "http://schema.org/speakable" + "specialCommitments", "http://schema.org/specialCommitments" + "specialOpeningHoursSpecification", "http://schema.org/specialOpeningHoursSpecification" + "specialty", "http://schema.org/specialty" + "speechToTextMarkup", "http://schema.org/speechToTextMarkup" + "speed", "http://schema.org/speed" + "spokenByCharacter", "http://schema.org/spokenByCharacter" + "sponsor", "http://schema.org/sponsor" + "sport", "http://schema.org/sport" + "sportsActivityLocation", "http://schema.org/sportsActivityLocation" + "sportsEvent", "http://schema.org/sportsEvent" + "sportsTeam", "http://schema.org/sportsTeam" + "spouse", "http://schema.org/spouse" + "stage", "http://schema.org/stage" + "stageAsNumber", "http://schema.org/stageAsNumber" + "starRating", "http://schema.org/starRating" + "startDate", "http://schema.org/startDate" + "startOffset", "http://schema.org/startOffset" + "startTime", "http://schema.org/startTime" + "statType", "http://schema.org/statType" + "status", "http://schema.org/status" + "steeringPosition", "http://schema.org/steeringPosition" + "step", "http://schema.org/step" + "stepValue", "http://schema.org/stepValue" + "steps", "http://schema.org/steps" + "storageRequirements", "http://schema.org/storageRequirements" + "streetAddress", "http://schema.org/streetAddress" + "strengthUnit", "http://schema.org/strengthUnit" + "strengthValue", "http://schema.org/strengthValue" + "structuralClass", "http://schema.org/structuralClass" + "study", "http://schema.org/study" + "studyDesign", "http://schema.org/studyDesign" + "studyLocation", "http://schema.org/studyLocation" + "studySubject", "http://schema.org/studySubject" + "stupidProperty", "http://schema.org/stupidProperty" + "subEvent", "http://schema.org/subEvent" + "subEvents", "http://schema.org/subEvents" + "subOrganization", "http://schema.org/subOrganization" + "subReservation", "http://schema.org/subReservation" + "subStageSuffix", "http://schema.org/subStageSuffix" + "subStructure", "http://schema.org/subStructure" + "subTest", "http://schema.org/subTest" + "subTrip", "http://schema.org/subTrip" + "subjectOf", "http://schema.org/subjectOf" + "subtitleLanguage", "http://schema.org/subtitleLanguage" + "successorOf", "http://schema.org/successorOf" + "sugarContent", "http://schema.org/sugarContent" + "suggestedAge", "http://schema.org/suggestedAge" + "suggestedAnswer", "http://schema.org/suggestedAnswer" + "suggestedGender", "http://schema.org/suggestedGender" + "suggestedMaxAge", "http://schema.org/suggestedMaxAge" + "suggestedMeasurement", "http://schema.org/suggestedMeasurement" + "suggestedMinAge", "http://schema.org/suggestedMinAge" + "suitableForDiet", "http://schema.org/suitableForDiet" + "superEvent", "http://schema.org/superEvent" + "supersededBy", "http://schema.org/supersededBy" + "supply", "http://schema.org/supply" + "supplyTo", "http://schema.org/supplyTo" + "supportingData", "http://schema.org/supportingData" + "surface", "http://schema.org/surface" + "syllabusSections", "http://schema.org/syllabusSections" + "target", "http://schema.org/target" + "targetCollection", "http://schema.org/targetCollection" + "targetDescription", "http://schema.org/targetDescription" + "targetName", "http://schema.org/targetName" + "targetPlatform", "http://schema.org/targetPlatform" + "targetPopulation", "http://schema.org/targetPopulation" + "targetProduct", "http://schema.org/targetProduct" + "targetUrl", "http://schema.org/targetUrl" + "taxID", "http://schema.org/taxID" + "taxonRank", "http://schema.org/taxonRank" + "taxonomicRange", "http://schema.org/taxonomicRange" + "teaches", "http://schema.org/teaches" + "telephone", "http://schema.org/telephone" + "temporal", "http://schema.org/temporal" + "temporalCoverage", "http://schema.org/temporalCoverage" + "termCode", "http://schema.org/termCode" + "termDuration", "http://schema.org/termDuration" + "termsOfService", "http://schema.org/termsOfService" + "termsPerYear", "http://schema.org/termsPerYear" + "text", "http://schema.org/text" + "textValue", "http://schema.org/textValue" + "thumbnail", "http://schema.org/thumbnail" + "thumbnailUrl", "http://schema.org/thumbnailUrl" + "tickerSymbol", "http://schema.org/tickerSymbol" + "ticketNumber", "http://schema.org/ticketNumber" + "ticketToken", "http://schema.org/ticketToken" + "ticketedSeat", "http://schema.org/ticketedSeat" + "timeOfDay", "http://schema.org/timeOfDay" + "timeRequired", "http://schema.org/timeRequired" + "timeToComplete", "http://schema.org/timeToComplete" + "tissueSample", "http://schema.org/tissueSample" + "title", "http://schema.org/title" + "titleEIDR", "http://schema.org/titleEIDR" + "toLocation", "http://schema.org/toLocation" + "toRecipient", "http://schema.org/toRecipient" + "tocContinuation", "http://schema.org/tocContinuation" + "tocEntry", "http://schema.org/tocEntry" + "tongueWeight", "http://schema.org/tongueWeight" + "tool", "http://schema.org/tool" + "torque", "http://schema.org/torque" + "totalHistoricalEnrollment", "http://schema.org/totalHistoricalEnrollment" + "totalJobOpenings", "http://schema.org/totalJobOpenings" + "totalPaymentDue", "http://schema.org/totalPaymentDue" + "totalPrice", "http://schema.org/totalPrice" + "totalTime", "http://schema.org/totalTime" + "tourBookingPage", "http://schema.org/tourBookingPage" + "touristType", "http://schema.org/touristType" + "track", "http://schema.org/track" + "trackingNumber", "http://schema.org/trackingNumber" + "trackingUrl", "http://schema.org/trackingUrl" + "tracks", "http://schema.org/tracks" + "trailer", "http://schema.org/trailer" + "trailerWeight", "http://schema.org/trailerWeight" + "trainName", "http://schema.org/trainName" + "trainNumber", "http://schema.org/trainNumber" + "trainingSalary", "http://schema.org/trainingSalary" + "transFatContent", "http://schema.org/transFatContent" + "transcript", "http://schema.org/transcript" + "transitTime", "http://schema.org/transitTime" + "transitTimeLabel", "http://schema.org/transitTimeLabel" + "translationOfWork", "http://schema.org/translationOfWork" + "translator", "http://schema.org/translator" + "transmissionMethod", "http://schema.org/transmissionMethod" + "travelBans", "http://schema.org/travelBans" + "trialDesign", "http://schema.org/trialDesign" + "tributary", "http://schema.org/tributary" + "tripOrigin", "http://schema.org/tripOrigin" + "typeOfBed", "http://schema.org/typeOfBed" + "typeOfGood", "http://schema.org/typeOfGood" + "typicalAgeRange", "http://schema.org/typicalAgeRange" + "typicalCreditsPerTerm", "http://schema.org/typicalCreditsPerTerm" + "typicalTest", "http://schema.org/typicalTest" + "underName", "http://schema.org/underName" + "unitCode", "http://schema.org/unitCode" + "unitText", "http://schema.org/unitText" + "unnamedSourcesPolicy", "http://schema.org/unnamedSourcesPolicy" + "unsaturatedFatContent", "http://schema.org/unsaturatedFatContent" + "uploadDate", "http://schema.org/uploadDate" + "upvoteCount", "http://schema.org/upvoteCount" + "url", "http://schema.org/url" + "urlTemplate", "http://schema.org/urlTemplate" + "usageInfo", "http://schema.org/usageInfo" + "usedToDiagnose", "http://schema.org/usedToDiagnose" + "userInteractionCount", "http://schema.org/userInteractionCount" + "usesDevice", "http://schema.org/usesDevice" + "usesHealthPlanIdStandard", "http://schema.org/usesHealthPlanIdStandard" + "utterances", "http://schema.org/utterances" + "validFor", "http://schema.org/validFor" + "validFrom", "http://schema.org/validFrom" + "validIn", "http://schema.org/validIn" + "validThrough", "http://schema.org/validThrough" + "validUntil", "http://schema.org/validUntil" + "value", "http://schema.org/value" + "valueAddedTaxIncluded", "http://schema.org/valueAddedTaxIncluded" + "valueMaxLength", "http://schema.org/valueMaxLength" + "valueMinLength", "http://schema.org/valueMinLength" + "valueName", "http://schema.org/valueName" + "valuePattern", "http://schema.org/valuePattern" + "valueReference", "http://schema.org/valueReference" + "valueRequired", "http://schema.org/valueRequired" + "variableMeasured", "http://schema.org/variableMeasured" + "variablesMeasured", "http://schema.org/variablesMeasured" + "variantCover", "http://schema.org/variantCover" + "variesBy", "http://schema.org/variesBy" + "vatID", "http://schema.org/vatID" + "vehicleConfiguration", "http://schema.org/vehicleConfiguration" + "vehicleEngine", "http://schema.org/vehicleEngine" + "vehicleIdentificationNumber", "http://schema.org/vehicleIdentificationNumber" + "vehicleInteriorColor", "http://schema.org/vehicleInteriorColor" + "vehicleInteriorType", "http://schema.org/vehicleInteriorType" + "vehicleModelDate", "http://schema.org/vehicleModelDate" + "vehicleSeatingCapacity", "http://schema.org/vehicleSeatingCapacity" + "vehicleSpecialUsage", "http://schema.org/vehicleSpecialUsage" + "vehicleTransmission", "http://schema.org/vehicleTransmission" + "vendor", "http://schema.org/vendor" + "verificationFactCheckingPolicy", "http://schema.org/verificationFactCheckingPolicy" + "version", "http://schema.org/version" + "video", "http://schema.org/video" + "videoFormat", "http://schema.org/videoFormat" + "videoFrameSize", "http://schema.org/videoFrameSize" + "videoQuality", "http://schema.org/videoQuality" + "volumeNumber", "http://schema.org/volumeNumber" + "warning", "http://schema.org/warning" + "warranty", "http://schema.org/warranty" + "warrantyPromise", "http://schema.org/warrantyPromise" + "warrantyScope", "http://schema.org/warrantyScope" + "webCheckinTime", "http://schema.org/webCheckinTime" + "webFeed", "http://schema.org/webFeed" + "weight", "http://schema.org/weight" + "weightTotal", "http://schema.org/weightTotal" + "wheelbase", "http://schema.org/wheelbase" + "width", "http://schema.org/width" + "winner", "http://schema.org/winner" + "wordCount", "http://schema.org/wordCount" + "workExample", "http://schema.org/workExample" + "workFeatured", "http://schema.org/workFeatured" + "workHours", "http://schema.org/workHours" + "workLocation", "http://schema.org/workLocation" + "workPerformed", "http://schema.org/workPerformed" + "workPresented", "http://schema.org/workPresented" + "workTranslation", "http://schema.org/workTranslation" + "workload", "http://schema.org/workload" + "worksFor", "http://schema.org/worksFor" + "worstRating", "http://schema.org/worstRating" + "xpath", "http://schema.org/xpath" + "yearBuilt", "http://schema.org/yearBuilt" + "yearlyRevenue", "http://schema.org/yearlyRevenue" + "yearsInOperation", "http://schema.org/yearsInOperation" + "yield", "http://schema.org/yield" + "File", "http://schema.org/MediaObject" + "path", "http://schema.org/contentUrl" + "Journal", "http://schema.org/Periodical" + "cite-as", "http://www.iana.org/assignments/relation/cite-as" + "hasFile", "http://pcdm.org/models#hasFile" + "hasMember", "http://pcdm.org/models#hasMember" + "RepositoryCollection", "http://pcdm.org/models#Collection" + "RepositoryObject", "http://pcdm.org/models#Object" + "RepositoryFile", "http://pcdm.org/models#File" + "ComputationalWorkflow", "https://bioschemas.org/ComputationalWorkflow" + "input", "https://bioschemas.org/ComputationalWorkflow#input" + "output", "https://bioschemas.org/ComputationalWorkflow#output" + "FormalParameter", "https://bioschemas.org/FormalParameter" + "wasDerivedFrom", "http://www.w3.org/ns/prov#wasDerivedFrom" + "importedFrom", "http://purl.org/pav/importedFrom" + "importedOn", "http://purl.org/pav/importedOn" + "importedBy", "http://purl.org/pav/importedBy" + "retrievedFrom", "http://purl.org/pav/retrievedFrom" + "retrievedOn", "http://purl.org/pav/retrievedOn" + "retrievedBy", "http://purl.org/pav/retrievedBy" + "conformsTo", "http://purl.org/dc/terms/conformsTo" + "Standard", "http://purl.org/dc/terms/Standard" + "hasArtifact", "http://www.w3.org/ns/dx/prof/hasArtifact" + "hasResource", "http://www.w3.org/ns/dx/prof/hasResource" + "hasRole", "http://www.w3.org/ns/dx/prof/hasRole" + "hasToken", "http://www.w3.org/ns/dx/prof/hasToken" + "isProfileOf", "http://www.w3.org/ns/dx/prof/isProfileOf" + "ResourceDescriptor", "http://www.w3.org/ns/dx/prof/ResourceDescriptor" + "ResourceRole", "http://www.w3.org/ns/dx/prof/ResourceRole" + "Profile", "http://www.w3.org/ns/dx/prof/Profile" + "softwareSuggestions", "https://codemeta.github.io/terms/softwareSuggestions" + "continuousIntegration", "https://codemeta.github.io/terms/continuousIntegration" + "buildInstructions", "https://codemeta.github.io/terms/buildInstructions" + "developmentStatus", "https://codemeta.github.io/terms/developmentStatus" + "embargoEndDate", "https://codemeta.github.io/terms/embargoEndDate" + "readme", "https://codemeta.github.io/terms/readme" + "issueTracker", "https://codemeta.github.io/terms/issueTracker" + "referencePublication", "https://codemeta.github.io/terms/referencePublication" + "hasSourceCode", "https://codemeta.github.io/terms/hasSourceCode" + "isSourceCodeOf", "https://codemeta.github.io/terms/isSourceCodeOf" + "Geometry", "http://www.opengis.net/ont/geosparql#Geometry" + "asWKT", "http://www.opengis.net/ont/geosparql#asWKT" + "pcdm", "http://pcdm.org/models#" + "bibo", "http://purl.org/ontology/bibo/" + "cc", "http://creativecommons.org/ns#" + "dct", "http://purl.org/dc/terms/" + "foaf", "http://xmlns.com/foaf/0.1/" + "prof", "http://www.w3.org/ns/dx/prof/" + "profrole", "http://www.w3.org/ns/dx/prof/role/" + "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + "rdfa", "http://www.w3.org/ns/rdfa#" + "rdfs", "http://www.w3.org/2000/01/rdf-schema#" + "schema", "http://schema.org/" + "frapo", "http://purl.org/cerif/frapo/" + "rel", "https://www.w3.org/ns/iana/link-relations/relation#" + "pav", "http://purl.org/pav/" + "prov", "http://www.w3.org/ns/prov#" + "wfdesc", "http://purl.org/ro/wfdesc#" + "wfprov", "http://purl.org/ro/wfprov#" + "roterms", "http://purl.org/ro/roterms#" + "relation", "http://www.iana.org/assignments/relation/" + "wf4ever", "http://purl.org/ro/wf4ever#" + "vann", "http://purl.org/vocab/vann/" + "geosparql", "http://www.opengis.net/ont/geosparql#" + """ + + let termsV1_1 = + """ + "3DModel", "http://schema.org/3DModel" + "AMRadioChannel", "http://schema.org/AMRadioChannel" + "APIReference", "http://schema.org/APIReference" + "Abdomen", "http://schema.org/Abdomen" + "AboutPage", "http://schema.org/AboutPage" + "AcceptAction", "http://schema.org/AcceptAction" + "Accommodation", "http://schema.org/Accommodation" + "AccountingService", "http://schema.org/AccountingService" + "AchieveAction", "http://schema.org/AchieveAction" + "Action", "http://schema.org/Action" + "ActionAccessSpecification", "http://schema.org/ActionAccessSpecification" + "ActionStatusType", "http://schema.org/ActionStatusType" + "ActivateAction", "http://schema.org/ActivateAction" + "ActiveActionStatus", "http://schema.org/ActiveActionStatus" + "ActiveNotRecruiting", "http://schema.org/ActiveNotRecruiting" + "AddAction", "http://schema.org/AddAction" + "AdministrativeArea", "http://schema.org/AdministrativeArea" + "AdultEntertainment", "http://schema.org/AdultEntertainment" + "AdvertiserContentArticle", "http://schema.org/AdvertiserContentArticle" + "AerobicActivity", "http://schema.org/AerobicActivity" + "AggregateOffer", "http://schema.org/AggregateOffer" + "AggregateRating", "http://schema.org/AggregateRating" + "AgreeAction", "http://schema.org/AgreeAction" + "Airline", "http://schema.org/Airline" + "Airport", "http://schema.org/Airport" + "AlbumRelease", "http://schema.org/AlbumRelease" + "AlignmentObject", "http://schema.org/AlignmentObject" + "AllWheelDriveConfiguration", "http://schema.org/AllWheelDriveConfiguration" + "AllocateAction", "http://schema.org/AllocateAction" + "AmusementPark", "http://schema.org/AmusementPark" + "AnaerobicActivity", "http://schema.org/AnaerobicActivity" + "AnalysisNewsArticle", "http://schema.org/AnalysisNewsArticle" + "AnatomicalStructure", "http://schema.org/AnatomicalStructure" + "AnatomicalSystem", "http://schema.org/AnatomicalSystem" + "Anesthesia", "http://schema.org/Anesthesia" + "AnimalShelter", "http://schema.org/AnimalShelter" + "Answer", "http://schema.org/Answer" + "Apartment", "http://schema.org/Apartment" + "ApartmentComplex", "http://schema.org/ApartmentComplex" + "Appearance", "http://schema.org/Appearance" + "AppendAction", "http://schema.org/AppendAction" + "ApplyAction", "http://schema.org/ApplyAction" + "ApprovedIndication", "http://schema.org/ApprovedIndication" + "Aquarium", "http://schema.org/Aquarium" + "ArchiveComponent", "http://schema.org/ArchiveComponent" + "ArchiveOrganization", "http://schema.org/ArchiveOrganization" + "ArriveAction", "http://schema.org/ArriveAction" + "ArtGallery", "http://schema.org/ArtGallery" + "Artery", "http://schema.org/Artery" + "Article", "http://schema.org/Article" + "AskAction", "http://schema.org/AskAction" + "AskPublicNewsArticle", "http://schema.org/AskPublicNewsArticle" + "AssessAction", "http://schema.org/AssessAction" + "AssignAction", "http://schema.org/AssignAction" + "Atlas", "http://schema.org/Atlas" + "Attorney", "http://schema.org/Attorney" + "Audience", "http://schema.org/Audience" + "AudioObject", "http://schema.org/AudioObject" + "Audiobook", "http://schema.org/Audiobook" + "AudiobookFormat", "http://schema.org/AudiobookFormat" + "AuthenticContent", "http://schema.org/AuthenticContent" + "AuthoritativeLegalValue", "http://schema.org/AuthoritativeLegalValue" + "AuthorizeAction", "http://schema.org/AuthorizeAction" + "AutoBodyShop", "http://schema.org/AutoBodyShop" + "AutoDealer", "http://schema.org/AutoDealer" + "AutoPartsStore", "http://schema.org/AutoPartsStore" + "AutoRental", "http://schema.org/AutoRental" + "AutoRepair", "http://schema.org/AutoRepair" + "AutoWash", "http://schema.org/AutoWash" + "AutomatedTeller", "http://schema.org/AutomatedTeller" + "AutomotiveBusiness", "http://schema.org/AutomotiveBusiness" + "Ayurvedic", "http://schema.org/Ayurvedic" + "BackgroundNewsArticle", "http://schema.org/BackgroundNewsArticle" + "Bacteria", "http://schema.org/Bacteria" + "Bakery", "http://schema.org/Bakery" + "Balance", "http://schema.org/Balance" + "BankAccount", "http://schema.org/BankAccount" + "BankOrCreditUnion", "http://schema.org/BankOrCreditUnion" + "BarOrPub", "http://schema.org/BarOrPub" + "Barcode", "http://schema.org/Barcode" + "BasicIncome", "http://schema.org/BasicIncome" + "Beach", "http://schema.org/Beach" + "BeautySalon", "http://schema.org/BeautySalon" + "BedAndBreakfast", "http://schema.org/BedAndBreakfast" + "BedDetails", "http://schema.org/BedDetails" + "BedType", "http://schema.org/BedType" + "BefriendAction", "http://schema.org/BefriendAction" + "BenefitsHealthAspect", "http://schema.org/BenefitsHealthAspect" + "BikeStore", "http://schema.org/BikeStore" + "Blog", "http://schema.org/Blog" + "BlogPosting", "http://schema.org/BlogPosting" + "BloodTest", "http://schema.org/BloodTest" + "BoardingPolicyType", "http://schema.org/BoardingPolicyType" + "BoatReservation", "http://schema.org/BoatReservation" + "BoatTerminal", "http://schema.org/BoatTerminal" + "BoatTrip", "http://schema.org/BoatTrip" + "BodyOfWater", "http://schema.org/BodyOfWater" + "Bone", "http://schema.org/Bone" + "Book", "http://schema.org/Book" + "BookFormatType", "http://schema.org/BookFormatType" + "BookSeries", "http://schema.org/BookSeries" + "BookStore", "http://schema.org/BookStore" + "BookmarkAction", "http://schema.org/BookmarkAction" + "Boolean", "http://schema.org/Boolean" + "BorrowAction", "http://schema.org/BorrowAction" + "BowlingAlley", "http://schema.org/BowlingAlley" + "BrainStructure", "http://schema.org/BrainStructure" + "Brand", "http://schema.org/Brand" + "BreadcrumbList", "http://schema.org/BreadcrumbList" + "Brewery", "http://schema.org/Brewery" + "Bridge", "http://schema.org/Bridge" + "BroadcastChannel", "http://schema.org/BroadcastChannel" + "BroadcastEvent", "http://schema.org/BroadcastEvent" + "BroadcastFrequencySpecification", "http://schema.org/BroadcastFrequencySpecification" + "BroadcastRelease", "http://schema.org/BroadcastRelease" + "BroadcastService", "http://schema.org/BroadcastService" + "BrokerageAccount", "http://schema.org/BrokerageAccount" + "BuddhistTemple", "http://schema.org/BuddhistTemple" + "BusOrCoach", "http://schema.org/BusOrCoach" + "BusReservation", "http://schema.org/BusReservation" + "BusStation", "http://schema.org/BusStation" + "BusStop", "http://schema.org/BusStop" + "BusTrip", "http://schema.org/BusTrip" + "BusinessAudience", "http://schema.org/BusinessAudience" + "BusinessEntityType", "http://schema.org/BusinessEntityType" + "BusinessEvent", "http://schema.org/BusinessEvent" + "BusinessFunction", "http://schema.org/BusinessFunction" + "BusinessSupport", "http://schema.org/BusinessSupport" + "BuyAction", "http://schema.org/BuyAction" + "CDCPMDRecord", "http://schema.org/CDCPMDRecord" + "CDFormat", "http://schema.org/CDFormat" + "CT", "http://schema.org/CT" + "CableOrSatelliteService", "http://schema.org/CableOrSatelliteService" + "CafeOrCoffeeShop", "http://schema.org/CafeOrCoffeeShop" + "Campground", "http://schema.org/Campground" + "CampingPitch", "http://schema.org/CampingPitch" + "Canal", "http://schema.org/Canal" + "CancelAction", "http://schema.org/CancelAction" + "Car", "http://schema.org/Car" + "CarUsageType", "http://schema.org/CarUsageType" + "Cardiovascular", "http://schema.org/Cardiovascular" + "CardiovascularExam", "http://schema.org/CardiovascularExam" + "CaseSeries", "http://schema.org/CaseSeries" + "Casino", "http://schema.org/Casino" + "CassetteFormat", "http://schema.org/CassetteFormat" + "CategoryCode", "http://schema.org/CategoryCode" + "CategoryCodeSet", "http://schema.org/CategoryCodeSet" + "CatholicChurch", "http://schema.org/CatholicChurch" + "CausesHealthAspect", "http://schema.org/CausesHealthAspect" + "Cemetery", "http://schema.org/Cemetery" + "Chapter", "http://schema.org/Chapter" + "CharitableIncorporatedOrganization", "http://schema.org/CharitableIncorporatedOrganization" + "CheckAction", "http://schema.org/CheckAction" + "CheckInAction", "http://schema.org/CheckInAction" + "CheckOutAction", "http://schema.org/CheckOutAction" + "CheckoutPage", "http://schema.org/CheckoutPage" + "ChildCare", "http://schema.org/ChildCare" + "ChildrensEvent", "http://schema.org/ChildrensEvent" + "Chiropractic", "http://schema.org/Chiropractic" + "ChooseAction", "http://schema.org/ChooseAction" + "Church", "http://schema.org/Church" + "City", "http://schema.org/City" + "CityHall", "http://schema.org/CityHall" + "CivicStructure", "http://schema.org/CivicStructure" + "Claim", "http://schema.org/Claim" + "ClaimReview", "http://schema.org/ClaimReview" + "Class", "http://schema.org/Class" + "Clinician", "http://schema.org/Clinician" + "Clip", "http://schema.org/Clip" + "ClothingStore", "http://schema.org/ClothingStore" + "CoOp", "http://schema.org/CoOp" + "Code", "http://schema.org/Code" + "CohortStudy", "http://schema.org/CohortStudy" + "Collection", "http://schema.org/Collection" + "CollectionPage", "http://schema.org/CollectionPage" + "CollegeOrUniversity", "http://schema.org/CollegeOrUniversity" + "ComedyClub", "http://schema.org/ComedyClub" + "ComedyEvent", "http://schema.org/ComedyEvent" + "ComicCoverArt", "http://schema.org/ComicCoverArt" + "ComicIssue", "http://schema.org/ComicIssue" + "ComicSeries", "http://schema.org/ComicSeries" + "ComicStory", "http://schema.org/ComicStory" + "Comment", "http://schema.org/Comment" + "CommentAction", "http://schema.org/CommentAction" + "CommentPermission", "http://schema.org/CommentPermission" + "CommunicateAction", "http://schema.org/CommunicateAction" + "CommunityHealth", "http://schema.org/CommunityHealth" + "CompilationAlbum", "http://schema.org/CompilationAlbum" + "CompleteDataFeed", "http://schema.org/CompleteDataFeed" + "Completed", "http://schema.org/Completed" + "CompletedActionStatus", "http://schema.org/CompletedActionStatus" + "CompoundPriceSpecification", "http://schema.org/CompoundPriceSpecification" + "ComputerLanguage", "http://schema.org/ComputerLanguage" + "ComputerStore", "http://schema.org/ComputerStore" + "ConfirmAction", "http://schema.org/ConfirmAction" + "Consortium", "http://schema.org/Consortium" + "ConsumeAction", "http://schema.org/ConsumeAction" + "ContactPage", "http://schema.org/ContactPage" + "ContactPoint", "http://schema.org/ContactPoint" + "ContactPointOption", "http://schema.org/ContactPointOption" + "ContagiousnessHealthAspect", "http://schema.org/ContagiousnessHealthAspect" + "Continent", "http://schema.org/Continent" + "ControlAction", "http://schema.org/ControlAction" + "ConvenienceStore", "http://schema.org/ConvenienceStore" + "Conversation", "http://schema.org/Conversation" + "CookAction", "http://schema.org/CookAction" + "Corporation", "http://schema.org/Corporation" + "CorrectionComment", "http://schema.org/CorrectionComment" + "Country", "http://schema.org/Country" + "Course", "http://schema.org/Course" + "CourseInstance", "http://schema.org/CourseInstance" + "Courthouse", "http://schema.org/Courthouse" + "CoverArt", "http://schema.org/CoverArt" + "CovidTestingFacility", "http://schema.org/CovidTestingFacility" + "CreateAction", "http://schema.org/CreateAction" + "CreativeWork", "http://schema.org/CreativeWork" + "CreativeWorkSeason", "http://schema.org/CreativeWorkSeason" + "CreativeWorkSeries", "http://schema.org/CreativeWorkSeries" + "CreditCard", "http://schema.org/CreditCard" + "Crematorium", "http://schema.org/Crematorium" + "CriticReview", "http://schema.org/CriticReview" + "CrossSectional", "http://schema.org/CrossSectional" + "CssSelectorType", "http://schema.org/CssSelectorType" + "CurrencyConversionService", "http://schema.org/CurrencyConversionService" + "DDxElement", "http://schema.org/DDxElement" + "DJMixAlbum", "http://schema.org/DJMixAlbum" + "DVDFormat", "http://schema.org/DVDFormat" + "DamagedCondition", "http://schema.org/DamagedCondition" + "DanceEvent", "http://schema.org/DanceEvent" + "DanceGroup", "http://schema.org/DanceGroup" + "DataCatalog", "http://schema.org/DataCatalog" + "DataDownload", "http://schema.org/DataDownload" + "DataFeed", "http://schema.org/DataFeed" + "DataFeedItem", "http://schema.org/DataFeedItem" + "DataType", "http://schema.org/DataType" + "Dataset", "http://schema.org/Dataset" + "Date", "http://schema.org/Date" + "DateTime", "http://schema.org/DateTime" + "DatedMoneySpecification", "http://schema.org/DatedMoneySpecification" + "DayOfWeek", "http://schema.org/DayOfWeek" + "DaySpa", "http://schema.org/DaySpa" + "DeactivateAction", "http://schema.org/DeactivateAction" + "DefenceEstablishment", "http://schema.org/DefenceEstablishment" + "DefinedRegion", "http://schema.org/DefinedRegion" + "DefinedTerm", "http://schema.org/DefinedTerm" + "DefinedTermSet", "http://schema.org/DefinedTermSet" + "DefinitiveLegalValue", "http://schema.org/DefinitiveLegalValue" + "DeleteAction", "http://schema.org/DeleteAction" + "DeliveryChargeSpecification", "http://schema.org/DeliveryChargeSpecification" + "DeliveryEvent", "http://schema.org/DeliveryEvent" + "DeliveryMethod", "http://schema.org/DeliveryMethod" + "DeliveryTimeSettings", "http://schema.org/DeliveryTimeSettings" + "Demand", "http://schema.org/Demand" + "DemoAlbum", "http://schema.org/DemoAlbum" + "Dentist", "http://schema.org/Dentist" + "Dentistry", "http://schema.org/Dentistry" + "DepartAction", "http://schema.org/DepartAction" + "DepartmentStore", "http://schema.org/DepartmentStore" + "DepositAccount", "http://schema.org/DepositAccount" + "Dermatologic", "http://schema.org/Dermatologic" + "Dermatology", "http://schema.org/Dermatology" + "DiabeticDiet", "http://schema.org/DiabeticDiet" + "Diagnostic", "http://schema.org/Diagnostic" + "DiagnosticLab", "http://schema.org/DiagnosticLab" + "DiagnosticProcedure", "http://schema.org/DiagnosticProcedure" + "Diet", "http://schema.org/Diet" + "DietNutrition", "http://schema.org/DietNutrition" + "DietarySupplement", "http://schema.org/DietarySupplement" + "DigitalAudioTapeFormat", "http://schema.org/DigitalAudioTapeFormat" + "DigitalDocument", "http://schema.org/DigitalDocument" + "DigitalDocumentPermission", "http://schema.org/DigitalDocumentPermission" + "DigitalDocumentPermissionType", "http://schema.org/DigitalDocumentPermissionType" + "DigitalFormat", "http://schema.org/DigitalFormat" + "DisabilitySupport", "http://schema.org/DisabilitySupport" + "DisagreeAction", "http://schema.org/DisagreeAction" + "Discontinued", "http://schema.org/Discontinued" + "DiscoverAction", "http://schema.org/DiscoverAction" + "DiscussionForumPosting", "http://schema.org/DiscussionForumPosting" + "DislikeAction", "http://schema.org/DislikeAction" + "Distance", "http://schema.org/Distance" + "Distillery", "http://schema.org/Distillery" + "DonateAction", "http://schema.org/DonateAction" + "DoseSchedule", "http://schema.org/DoseSchedule" + "DoubleBlindedTrial", "http://schema.org/DoubleBlindedTrial" + "DownloadAction", "http://schema.org/DownloadAction" + "DrawAction", "http://schema.org/DrawAction" + "Drawing", "http://schema.org/Drawing" + "DrinkAction", "http://schema.org/DrinkAction" + "DriveWheelConfigurationValue", "http://schema.org/DriveWheelConfigurationValue" + "DrivingSchoolVehicleUsage", "http://schema.org/DrivingSchoolVehicleUsage" + "Drug", "http://schema.org/Drug" + "DrugClass", "http://schema.org/DrugClass" + "DrugCost", "http://schema.org/DrugCost" + "DrugCostCategory", "http://schema.org/DrugCostCategory" + "DrugLegalStatus", "http://schema.org/DrugLegalStatus" + "DrugPregnancyCategory", "http://schema.org/DrugPregnancyCategory" + "DrugPrescriptionStatus", "http://schema.org/DrugPrescriptionStatus" + "DrugStrength", "http://schema.org/DrugStrength" + "DryCleaningOrLaundry", "http://schema.org/DryCleaningOrLaundry" + "Duration", "http://schema.org/Duration" + "EBook", "http://schema.org/EBook" + "EPRelease", "http://schema.org/EPRelease" + "EUEnergyEfficiencyCategoryA", "http://schema.org/EUEnergyEfficiencyCategoryA" + "EUEnergyEfficiencyCategoryA1Plus", "http://schema.org/EUEnergyEfficiencyCategoryA1Plus" + "EUEnergyEfficiencyCategoryA2Plus", "http://schema.org/EUEnergyEfficiencyCategoryA2Plus" + "EUEnergyEfficiencyCategoryA3Plus", "http://schema.org/EUEnergyEfficiencyCategoryA3Plus" + "EUEnergyEfficiencyCategoryB", "http://schema.org/EUEnergyEfficiencyCategoryB" + "EUEnergyEfficiencyCategoryC", "http://schema.org/EUEnergyEfficiencyCategoryC" + "EUEnergyEfficiencyCategoryD", "http://schema.org/EUEnergyEfficiencyCategoryD" + "EUEnergyEfficiencyCategoryE", "http://schema.org/EUEnergyEfficiencyCategoryE" + "EUEnergyEfficiencyCategoryF", "http://schema.org/EUEnergyEfficiencyCategoryF" + "EUEnergyEfficiencyCategoryG", "http://schema.org/EUEnergyEfficiencyCategoryG" + "EUEnergyEfficiencyEnumeration", "http://schema.org/EUEnergyEfficiencyEnumeration" + "Ear", "http://schema.org/Ear" + "EatAction", "http://schema.org/EatAction" + "EducationEvent", "http://schema.org/EducationEvent" + "EducationalAudience", "http://schema.org/EducationalAudience" + "EducationalOccupationalCredential", "http://schema.org/EducationalOccupationalCredential" + "EducationalOccupationalProgram", "http://schema.org/EducationalOccupationalProgram" + "EducationalOrganization", "http://schema.org/EducationalOrganization" + "Electrician", "http://schema.org/Electrician" + "ElectronicsStore", "http://schema.org/ElectronicsStore" + "ElementarySchool", "http://schema.org/ElementarySchool" + "EmailMessage", "http://schema.org/EmailMessage" + "Embassy", "http://schema.org/Embassy" + "Emergency", "http://schema.org/Emergency" + "EmergencyService", "http://schema.org/EmergencyService" + "EmployeeRole", "http://schema.org/EmployeeRole" + "EmployerAggregateRating", "http://schema.org/EmployerAggregateRating" + "EmployerReview", "http://schema.org/EmployerReview" + "EmploymentAgency", "http://schema.org/EmploymentAgency" + "Endocrine", "http://schema.org/Endocrine" + "EndorseAction", "http://schema.org/EndorseAction" + "EndorsementRating", "http://schema.org/EndorsementRating" + "Energy", "http://schema.org/Energy" + "EnergyConsumptionDetails", "http://schema.org/EnergyConsumptionDetails" + "EnergyEfficiencyEnumeration", "http://schema.org/EnergyEfficiencyEnumeration" + "EnergyStarCertified", "http://schema.org/EnergyStarCertified" + "EnergyStarEnergyEfficiencyEnumeration", "http://schema.org/EnergyStarEnergyEfficiencyEnumeration" + "EngineSpecification", "http://schema.org/EngineSpecification" + "EnrollingByInvitation", "http://schema.org/EnrollingByInvitation" + "EntertainmentBusiness", "http://schema.org/EntertainmentBusiness" + "EntryPoint", "http://schema.org/EntryPoint" + "Enumeration", "http://schema.org/Enumeration" + "Episode", "http://schema.org/Episode" + "Event", "http://schema.org/Event" + "EventAttendanceModeEnumeration", "http://schema.org/EventAttendanceModeEnumeration" + "EventCancelled", "http://schema.org/EventCancelled" + "EventMovedOnline", "http://schema.org/EventMovedOnline" + "EventPostponed", "http://schema.org/EventPostponed" + "EventRescheduled", "http://schema.org/EventRescheduled" + "EventReservation", "http://schema.org/EventReservation" + "EventScheduled", "http://schema.org/EventScheduled" + "EventSeries", "http://schema.org/EventSeries" + "EventStatusType", "http://schema.org/EventStatusType" + "EventVenue", "http://schema.org/EventVenue" + "EvidenceLevelA", "http://schema.org/EvidenceLevelA" + "EvidenceLevelB", "http://schema.org/EvidenceLevelB" + "EvidenceLevelC", "http://schema.org/EvidenceLevelC" + "ExchangeRateSpecification", "http://schema.org/ExchangeRateSpecification" + "ExchangeRefund", "http://schema.org/ExchangeRefund" + "ExerciseAction", "http://schema.org/ExerciseAction" + "ExerciseGym", "http://schema.org/ExerciseGym" + "ExercisePlan", "http://schema.org/ExercisePlan" + "ExhibitionEvent", "http://schema.org/ExhibitionEvent" + "Eye", "http://schema.org/Eye" + "FAQPage", "http://schema.org/FAQPage" + "FDAcategoryA", "http://schema.org/FDAcategoryA" + "FDAcategoryB", "http://schema.org/FDAcategoryB" + "FDAcategoryC", "http://schema.org/FDAcategoryC" + "FDAcategoryD", "http://schema.org/FDAcategoryD" + "FDAcategoryX", "http://schema.org/FDAcategoryX" + "FDAnotEvaluated", "http://schema.org/FDAnotEvaluated" + "FMRadioChannel", "http://schema.org/FMRadioChannel" + "FailedActionStatus", "http://schema.org/FailedActionStatus" + "False", "http://schema.org/False" + "FastFoodRestaurant", "http://schema.org/FastFoodRestaurant" + "Female", "http://schema.org/Female" + "Festival", "http://schema.org/Festival" + "FilmAction", "http://schema.org/FilmAction" + "FinancialProduct", "http://schema.org/FinancialProduct" + "FinancialService", "http://schema.org/FinancialService" + "FindAction", "http://schema.org/FindAction" + "FireStation", "http://schema.org/FireStation" + "Flexibility", "http://schema.org/Flexibility" + "Flight", "http://schema.org/Flight" + "FlightReservation", "http://schema.org/FlightReservation" + "Float", "http://schema.org/Float" + "FloorPlan", "http://schema.org/FloorPlan" + "Florist", "http://schema.org/Florist" + "FollowAction", "http://schema.org/FollowAction" + "FoodEstablishment", "http://schema.org/FoodEstablishment" + "FoodEstablishmentReservation", "http://schema.org/FoodEstablishmentReservation" + "FoodEvent", "http://schema.org/FoodEvent" + "FoodService", "http://schema.org/FoodService" + "FourWheelDriveConfiguration", "http://schema.org/FourWheelDriveConfiguration" + "Friday", "http://schema.org/Friday" + "FrontWheelDriveConfiguration", "http://schema.org/FrontWheelDriveConfiguration" + "FullRefund", "http://schema.org/FullRefund" + "FundingAgency", "http://schema.org/FundingAgency" + "FundingScheme", "http://schema.org/FundingScheme" + "Fungus", "http://schema.org/Fungus" + "FurnitureStore", "http://schema.org/FurnitureStore" + "Game", "http://schema.org/Game" + "GamePlayMode", "http://schema.org/GamePlayMode" + "GameServer", "http://schema.org/GameServer" + "GameServerStatus", "http://schema.org/GameServerStatus" + "GardenStore", "http://schema.org/GardenStore" + "GasStation", "http://schema.org/GasStation" + "Gastroenterologic", "http://schema.org/Gastroenterologic" + "GatedResidenceCommunity", "http://schema.org/GatedResidenceCommunity" + "GenderType", "http://schema.org/GenderType" + "GeneralContractor", "http://schema.org/GeneralContractor" + "Genetic", "http://schema.org/Genetic" + "Genitourinary", "http://schema.org/Genitourinary" + "GeoCircle", "http://schema.org/GeoCircle" + "GeoCoordinates", "http://schema.org/GeoCoordinates" + "GeoShape", "http://schema.org/GeoShape" + "GeospatialGeometry", "http://schema.org/GeospatialGeometry" + "Geriatric", "http://schema.org/Geriatric" + "GiveAction", "http://schema.org/GiveAction" + "GlutenFreeDiet", "http://schema.org/GlutenFreeDiet" + "GolfCourse", "http://schema.org/GolfCourse" + "GovernmentBenefitsType", "http://schema.org/GovernmentBenefitsType" + "GovernmentBuilding", "http://schema.org/GovernmentBuilding" + "GovernmentOffice", "http://schema.org/GovernmentOffice" + "GovernmentOrganization", "http://schema.org/GovernmentOrganization" + "GovernmentPermit", "http://schema.org/GovernmentPermit" + "GovernmentService", "http://schema.org/GovernmentService" + "Grant", "http://schema.org/Grant" + "GraphicNovel", "http://schema.org/GraphicNovel" + "GroceryStore", "http://schema.org/GroceryStore" + "GroupBoardingPolicy", "http://schema.org/GroupBoardingPolicy" + "Guide", "http://schema.org/Guide" + "Gynecologic", "http://schema.org/Gynecologic" + "HTML", "rdf,HTML" + "HVACBusiness", "http://schema.org/HVACBusiness" + "Hackathon", "http://schema.org/Hackathon" + "HairSalon", "http://schema.org/HairSalon" + "HalalDiet", "http://schema.org/HalalDiet" + "Hardcover", "http://schema.org/Hardcover" + "HardwareStore", "http://schema.org/HardwareStore" + "Head", "http://schema.org/Head" + "HealthAndBeautyBusiness", "http://schema.org/HealthAndBeautyBusiness" + "HealthAspectEnumeration", "http://schema.org/HealthAspectEnumeration" + "HealthCare", "http://schema.org/HealthCare" + "HealthClub", "http://schema.org/HealthClub" + "HealthInsurancePlan", "http://schema.org/HealthInsurancePlan" + "HealthPlanCostSharingSpecification", "http://schema.org/HealthPlanCostSharingSpecification" + "HealthPlanFormulary", "http://schema.org/HealthPlanFormulary" + "HealthPlanNetwork", "http://schema.org/HealthPlanNetwork" + "HealthTopicContent", "http://schema.org/HealthTopicContent" + "HearingImpairedSupported", "http://schema.org/HearingImpairedSupported" + "Hematologic", "http://schema.org/Hematologic" + "HighSchool", "http://schema.org/HighSchool" + "HinduDiet", "http://schema.org/HinduDiet" + "HinduTemple", "http://schema.org/HinduTemple" + "HobbyShop", "http://schema.org/HobbyShop" + "HomeAndConstructionBusiness", "http://schema.org/HomeAndConstructionBusiness" + "HomeGoodsStore", "http://schema.org/HomeGoodsStore" + "Homeopathic", "http://schema.org/Homeopathic" + "Hospital", "http://schema.org/Hospital" + "Hostel", "http://schema.org/Hostel" + "Hotel", "http://schema.org/Hotel" + "HotelRoom", "http://schema.org/HotelRoom" + "House", "http://schema.org/House" + "HousePainter", "http://schema.org/HousePainter" + "HowOrWhereHealthAspect", "http://schema.org/HowOrWhereHealthAspect" + "HowTo", "http://schema.org/HowTo" + "HowToDirection", "http://schema.org/HowToDirection" + "HowToItem", "http://schema.org/HowToItem" + "HowToSection", "http://schema.org/HowToSection" + "HowToStep", "http://schema.org/HowToStep" + "HowToSupply", "http://schema.org/HowToSupply" + "HowToTip", "http://schema.org/HowToTip" + "HowToTool", "http://schema.org/HowToTool" + "IceCreamShop", "http://schema.org/IceCreamShop" + "IgnoreAction", "http://schema.org/IgnoreAction" + "ImageGallery", "http://schema.org/ImageGallery" + "ImageObject", "http://schema.org/ImageObject" + "ImagingTest", "http://schema.org/ImagingTest" + "InForce", "http://schema.org/InForce" + "InStock", "http://schema.org/InStock" + "InStoreOnly", "http://schema.org/InStoreOnly" + "IndividualProduct", "http://schema.org/IndividualProduct" + "Infectious", "http://schema.org/Infectious" + "InfectiousAgentClass", "http://schema.org/InfectiousAgentClass" + "InfectiousDisease", "http://schema.org/InfectiousDisease" + "InformAction", "http://schema.org/InformAction" + "InsertAction", "http://schema.org/InsertAction" + "InstallAction", "http://schema.org/InstallAction" + "InsuranceAgency", "http://schema.org/InsuranceAgency" + "Intangible", "http://schema.org/Intangible" + "Integer", "http://schema.org/Integer" + "InteractAction", "http://schema.org/InteractAction" + "InteractionCounter", "http://schema.org/InteractionCounter" + "InternationalTrial", "http://schema.org/InternationalTrial" + "InternetCafe", "http://schema.org/InternetCafe" + "InvestmentFund", "http://schema.org/InvestmentFund" + "InvestmentOrDeposit", "http://schema.org/InvestmentOrDeposit" + "InviteAction", "http://schema.org/InviteAction" + "Invoice", "http://schema.org/Invoice" + "ItemAvailability", "http://schema.org/ItemAvailability" + "ItemList", "http://schema.org/ItemList" + "ItemListOrderAscending", "http://schema.org/ItemListOrderAscending" + "ItemListOrderDescending", "http://schema.org/ItemListOrderDescending" + "ItemListOrderType", "http://schema.org/ItemListOrderType" + "ItemListUnordered", "http://schema.org/ItemListUnordered" + "ItemPage", "http://schema.org/ItemPage" + "JewelryStore", "http://schema.org/JewelryStore" + "JobPosting", "http://schema.org/JobPosting" + "JoinAction", "http://schema.org/JoinAction" + "Joint", "http://schema.org/Joint" + "KosherDiet", "http://schema.org/KosherDiet" + "LaboratoryScience", "http://schema.org/LaboratoryScience" + "LakeBodyOfWater", "http://schema.org/LakeBodyOfWater" + "Landform", "http://schema.org/Landform" + "LandmarksOrHistoricalBuildings", "http://schema.org/LandmarksOrHistoricalBuildings" + "Language", "http://schema.org/Language" + "LaserDiscFormat", "http://schema.org/LaserDiscFormat" + "LearningResource", "http://schema.org/LearningResource" + "LeaveAction", "http://schema.org/LeaveAction" + "LeftHandDriving", "http://schema.org/LeftHandDriving" + "LegalForceStatus", "http://schema.org/LegalForceStatus" + "LegalService", "http://schema.org/LegalService" + "LegalValueLevel", "http://schema.org/LegalValueLevel" + "Legislation", "http://schema.org/Legislation" + "LegislationObject", "http://schema.org/LegislationObject" + "LegislativeBuilding", "http://schema.org/LegislativeBuilding" + "LeisureTimeActivity", "http://schema.org/LeisureTimeActivity" + "LendAction", "http://schema.org/LendAction" + "Library", "http://schema.org/Library" + "LibrarySystem", "http://schema.org/LibrarySystem" + "LifestyleModification", "http://schema.org/LifestyleModification" + "Ligament", "http://schema.org/Ligament" + "LikeAction", "http://schema.org/LikeAction" + "LimitedAvailability", "http://schema.org/LimitedAvailability" + "LimitedByGuaranteeCharity", "http://schema.org/LimitedByGuaranteeCharity" + "LinkRole", "http://schema.org/LinkRole" + "LiquorStore", "http://schema.org/LiquorStore" + "ListItem", "http://schema.org/ListItem" + "ListenAction", "http://schema.org/ListenAction" + "LiteraryEvent", "http://schema.org/LiteraryEvent" + "LiveAlbum", "http://schema.org/LiveAlbum" + "LiveBlogPosting", "http://schema.org/LiveBlogPosting" + "LivingWithHealthAspect", "http://schema.org/LivingWithHealthAspect" + "LoanOrCredit", "http://schema.org/LoanOrCredit" + "LocalBusiness", "http://schema.org/LocalBusiness" + "LocationFeatureSpecification", "http://schema.org/LocationFeatureSpecification" + "LockerDelivery", "http://schema.org/LockerDelivery" + "Locksmith", "http://schema.org/Locksmith" + "LodgingBusiness", "http://schema.org/LodgingBusiness" + "LodgingReservation", "http://schema.org/LodgingReservation" + "Longitudinal", "http://schema.org/Longitudinal" + "LoseAction", "http://schema.org/LoseAction" + "LowCalorieDiet", "http://schema.org/LowCalorieDiet" + "LowFatDiet", "http://schema.org/LowFatDiet" + "LowLactoseDiet", "http://schema.org/LowLactoseDiet" + "LowSaltDiet", "http://schema.org/LowSaltDiet" + "Lung", "http://schema.org/Lung" + "LymphaticVessel", "http://schema.org/LymphaticVessel" + "MRI", "http://schema.org/MRI" + "Male", "http://schema.org/Male" + "Manuscript", "http://schema.org/Manuscript" + "Map", "http://schema.org/Map" + "MapCategoryType", "http://schema.org/MapCategoryType" + "MarryAction", "http://schema.org/MarryAction" + "Mass", "http://schema.org/Mass" + "MaximumDoseSchedule", "http://schema.org/MaximumDoseSchedule" + "MayTreatHealthAspect", "http://schema.org/MayTreatHealthAspect" + "MediaGallery", "http://schema.org/MediaGallery" + "MediaManipulationRatingEnumeration", "http://schema.org/MediaManipulationRatingEnumeration" + "MediaObject", "http://schema.org/MediaObject" + "MediaReview", "http://schema.org/MediaReview" + "MediaSubscription", "http://schema.org/MediaSubscription" + "MedicalAudience", "http://schema.org/MedicalAudience" + "MedicalAudienceType", "http://schema.org/MedicalAudienceType" + "MedicalBusiness", "http://schema.org/MedicalBusiness" + "MedicalCause", "http://schema.org/MedicalCause" + "MedicalClinic", "http://schema.org/MedicalClinic" + "MedicalCode", "http://schema.org/MedicalCode" + "MedicalCondition", "http://schema.org/MedicalCondition" + "MedicalConditionStage", "http://schema.org/MedicalConditionStage" + "MedicalContraindication", "http://schema.org/MedicalContraindication" + "MedicalDevice", "http://schema.org/MedicalDevice" + "MedicalDevicePurpose", "http://schema.org/MedicalDevicePurpose" + "MedicalEntity", "http://schema.org/MedicalEntity" + "MedicalEnumeration", "http://schema.org/MedicalEnumeration" + "MedicalEvidenceLevel", "http://schema.org/MedicalEvidenceLevel" + "MedicalGuideline", "http://schema.org/MedicalGuideline" + "MedicalGuidelineContraindication", "http://schema.org/MedicalGuidelineContraindication" + "MedicalGuidelineRecommendation", "http://schema.org/MedicalGuidelineRecommendation" + "MedicalImagingTechnique", "http://schema.org/MedicalImagingTechnique" + "MedicalIndication", "http://schema.org/MedicalIndication" + "MedicalIntangible", "http://schema.org/MedicalIntangible" + "MedicalObservationalStudy", "http://schema.org/MedicalObservationalStudy" + "MedicalObservationalStudyDesign", "http://schema.org/MedicalObservationalStudyDesign" + "MedicalOrganization", "http://schema.org/MedicalOrganization" + "MedicalProcedure", "http://schema.org/MedicalProcedure" + "MedicalProcedureType", "http://schema.org/MedicalProcedureType" + "MedicalResearcher", "http://schema.org/MedicalResearcher" + "MedicalRiskCalculator", "http://schema.org/MedicalRiskCalculator" + "MedicalRiskEstimator", "http://schema.org/MedicalRiskEstimator" + "MedicalRiskFactor", "http://schema.org/MedicalRiskFactor" + "MedicalRiskScore", "http://schema.org/MedicalRiskScore" + "MedicalScholarlyArticle", "http://schema.org/MedicalScholarlyArticle" + "MedicalSign", "http://schema.org/MedicalSign" + "MedicalSignOrSymptom", "http://schema.org/MedicalSignOrSymptom" + "MedicalSpecialty", "http://schema.org/MedicalSpecialty" + "MedicalStudy", "http://schema.org/MedicalStudy" + "MedicalStudyStatus", "http://schema.org/MedicalStudyStatus" + "MedicalSymptom", "http://schema.org/MedicalSymptom" + "MedicalTest", "http://schema.org/MedicalTest" + "MedicalTestPanel", "http://schema.org/MedicalTestPanel" + "MedicalTherapy", "http://schema.org/MedicalTherapy" + "MedicalTrial", "http://schema.org/MedicalTrial" + "MedicalTrialDesign", "http://schema.org/MedicalTrialDesign" + "MedicalWebPage", "http://schema.org/MedicalWebPage" + "MedicineSystem", "http://schema.org/MedicineSystem" + "MeetingRoom", "http://schema.org/MeetingRoom" + "MensClothingStore", "http://schema.org/MensClothingStore" + "Menu", "http://schema.org/Menu" + "MenuItem", "http://schema.org/MenuItem" + "MenuSection", "http://schema.org/MenuSection" + "MerchantReturnEnumeration", "http://schema.org/MerchantReturnEnumeration" + "MerchantReturnFiniteReturnWindow", "http://schema.org/MerchantReturnFiniteReturnWindow" + "MerchantReturnNotPermitted", "http://schema.org/MerchantReturnNotPermitted" + "MerchantReturnPolicy", "http://schema.org/MerchantReturnPolicy" + "MerchantReturnUnlimitedWindow", "http://schema.org/MerchantReturnUnlimitedWindow" + "MerchantReturnUnspecified", "http://schema.org/MerchantReturnUnspecified" + "Message", "http://schema.org/Message" + "MiddleSchool", "http://schema.org/MiddleSchool" + "Midwifery", "http://schema.org/Midwifery" + "MisconceptionsHealthAspect", "http://schema.org/MisconceptionsHealthAspect" + "MissingContext", "http://schema.org/MissingContext" + "MixedEventAttendanceMode", "http://schema.org/MixedEventAttendanceMode" + "MixtapeAlbum", "http://schema.org/MixtapeAlbum" + "MobileApplication", "http://schema.org/MobileApplication" + "MobilePhoneStore", "http://schema.org/MobilePhoneStore" + "Monday", "http://schema.org/Monday" + "MonetaryAmount", "http://schema.org/MonetaryAmount" + "MonetaryAmountDistribution", "http://schema.org/MonetaryAmountDistribution" + "MonetaryGrant", "http://schema.org/MonetaryGrant" + "MoneyTransfer", "http://schema.org/MoneyTransfer" + "MortgageLoan", "http://schema.org/MortgageLoan" + "Mosque", "http://schema.org/Mosque" + "Motel", "http://schema.org/Motel" + "Motorcycle", "http://schema.org/Motorcycle" + "MotorcycleDealer", "http://schema.org/MotorcycleDealer" + "MotorcycleRepair", "http://schema.org/MotorcycleRepair" + "MotorizedBicycle", "http://schema.org/MotorizedBicycle" + "Mountain", "http://schema.org/Mountain" + "MoveAction", "http://schema.org/MoveAction" + "Movie", "http://schema.org/Movie" + "MovieClip", "http://schema.org/MovieClip" + "MovieRentalStore", "http://schema.org/MovieRentalStore" + "MovieSeries", "http://schema.org/MovieSeries" + "MovieTheater", "http://schema.org/MovieTheater" + "MovingCompany", "http://schema.org/MovingCompany" + "MultiCenterTrial", "http://schema.org/MultiCenterTrial" + "MultiPlayer", "http://schema.org/MultiPlayer" + "MulticellularParasite", "http://schema.org/MulticellularParasite" + "Muscle", "http://schema.org/Muscle" + "Musculoskeletal", "http://schema.org/Musculoskeletal" + "MusculoskeletalExam", "http://schema.org/MusculoskeletalExam" + "Museum", "http://schema.org/Museum" + "MusicAlbum", "http://schema.org/MusicAlbum" + "MusicAlbumProductionType", "http://schema.org/MusicAlbumProductionType" + "MusicAlbumReleaseType", "http://schema.org/MusicAlbumReleaseType" + "MusicComposition", "http://schema.org/MusicComposition" + "MusicEvent", "http://schema.org/MusicEvent" + "MusicGroup", "http://schema.org/MusicGroup" + "MusicPlaylist", "http://schema.org/MusicPlaylist" + "MusicRecording", "http://schema.org/MusicRecording" + "MusicRelease", "http://schema.org/MusicRelease" + "MusicReleaseFormatType", "http://schema.org/MusicReleaseFormatType" + "MusicStore", "http://schema.org/MusicStore" + "MusicVenue", "http://schema.org/MusicVenue" + "MusicVideoObject", "http://schema.org/MusicVideoObject" + "NGO", "http://schema.org/NGO" + "NLNonprofitType", "http://schema.org/NLNonprofitType" + "NailSalon", "http://schema.org/NailSalon" + "Neck", "http://schema.org/Neck" + "Nerve", "http://schema.org/Nerve" + "Neuro", "http://schema.org/Neuro" + "Neurologic", "http://schema.org/Neurologic" + "NewCondition", "http://schema.org/NewCondition" + "NewsArticle", "http://schema.org/NewsArticle" + "NewsMediaOrganization", "http://schema.org/NewsMediaOrganization" + "Newspaper", "http://schema.org/Newspaper" + "NightClub", "http://schema.org/NightClub" + "NoninvasiveProcedure", "http://schema.org/NoninvasiveProcedure" + "Nonprofit501a", "http://schema.org/Nonprofit501a" + "Nonprofit501c1", "http://schema.org/Nonprofit501c1" + "Nonprofit501c10", "http://schema.org/Nonprofit501c10" + "Nonprofit501c11", "http://schema.org/Nonprofit501c11" + "Nonprofit501c12", "http://schema.org/Nonprofit501c12" + "Nonprofit501c13", "http://schema.org/Nonprofit501c13" + "Nonprofit501c14", "http://schema.org/Nonprofit501c14" + "Nonprofit501c15", "http://schema.org/Nonprofit501c15" + "Nonprofit501c16", "http://schema.org/Nonprofit501c16" + "Nonprofit501c17", "http://schema.org/Nonprofit501c17" + "Nonprofit501c18", "http://schema.org/Nonprofit501c18" + "Nonprofit501c19", "http://schema.org/Nonprofit501c19" + "Nonprofit501c2", "http://schema.org/Nonprofit501c2" + "Nonprofit501c20", "http://schema.org/Nonprofit501c20" + "Nonprofit501c21", "http://schema.org/Nonprofit501c21" + "Nonprofit501c22", "http://schema.org/Nonprofit501c22" + "Nonprofit501c23", "http://schema.org/Nonprofit501c23" + "Nonprofit501c24", "http://schema.org/Nonprofit501c24" + "Nonprofit501c25", "http://schema.org/Nonprofit501c25" + "Nonprofit501c26", "http://schema.org/Nonprofit501c26" + "Nonprofit501c27", "http://schema.org/Nonprofit501c27" + "Nonprofit501c28", "http://schema.org/Nonprofit501c28" + "Nonprofit501c3", "http://schema.org/Nonprofit501c3" + "Nonprofit501c4", "http://schema.org/Nonprofit501c4" + "Nonprofit501c5", "http://schema.org/Nonprofit501c5" + "Nonprofit501c6", "http://schema.org/Nonprofit501c6" + "Nonprofit501c7", "http://schema.org/Nonprofit501c7" + "Nonprofit501c8", "http://schema.org/Nonprofit501c8" + "Nonprofit501c9", "http://schema.org/Nonprofit501c9" + "Nonprofit501d", "http://schema.org/Nonprofit501d" + "Nonprofit501e", "http://schema.org/Nonprofit501e" + "Nonprofit501f", "http://schema.org/Nonprofit501f" + "Nonprofit501k", "http://schema.org/Nonprofit501k" + "Nonprofit501n", "http://schema.org/Nonprofit501n" + "Nonprofit501q", "http://schema.org/Nonprofit501q" + "Nonprofit527", "http://schema.org/Nonprofit527" + "NonprofitANBI", "http://schema.org/NonprofitANBI" + "NonprofitSBBI", "http://schema.org/NonprofitSBBI" + "NonprofitType", "http://schema.org/NonprofitType" + "Nose", "http://schema.org/Nose" + "NotInForce", "http://schema.org/NotInForce" + "NotYetRecruiting", "http://schema.org/NotYetRecruiting" + "Notary", "http://schema.org/Notary" + "NoteDigitalDocument", "http://schema.org/NoteDigitalDocument" + "Number", "http://schema.org/Number" + "Nursing", "http://schema.org/Nursing" + "NutritionInformation", "http://schema.org/NutritionInformation" + "OTC", "http://schema.org/OTC" + "Observation", "http://schema.org/Observation" + "Observational", "http://schema.org/Observational" + "Obstetric", "http://schema.org/Obstetric" + "Occupation", "http://schema.org/Occupation" + "OccupationalActivity", "http://schema.org/OccupationalActivity" + "OccupationalTherapy", "http://schema.org/OccupationalTherapy" + "OceanBodyOfWater", "http://schema.org/OceanBodyOfWater" + "Offer", "http://schema.org/Offer" + "OfferCatalog", "http://schema.org/OfferCatalog" + "OfferForLease", "http://schema.org/OfferForLease" + "OfferForPurchase", "http://schema.org/OfferForPurchase" + "OfferItemCondition", "http://schema.org/OfferItemCondition" + "OfferShippingDetails", "http://schema.org/OfferShippingDetails" + "OfficeEquipmentStore", "http://schema.org/OfficeEquipmentStore" + "OfficialLegalValue", "http://schema.org/OfficialLegalValue" + "OfflineEventAttendanceMode", "http://schema.org/OfflineEventAttendanceMode" + "OfflinePermanently", "http://schema.org/OfflinePermanently" + "OfflineTemporarily", "http://schema.org/OfflineTemporarily" + "OnDemandEvent", "http://schema.org/OnDemandEvent" + "OnSitePickup", "http://schema.org/OnSitePickup" + "Oncologic", "http://schema.org/Oncologic" + "OneTimePayments", "http://schema.org/OneTimePayments" + "Online", "http://schema.org/Online" + "OnlineEventAttendanceMode", "http://schema.org/OnlineEventAttendanceMode" + "OnlineFull", "http://schema.org/OnlineFull" + "OnlineOnly", "http://schema.org/OnlineOnly" + "OpenTrial", "http://schema.org/OpenTrial" + "OpeningHoursSpecification", "http://schema.org/OpeningHoursSpecification" + "OpinionNewsArticle", "http://schema.org/OpinionNewsArticle" + "Optician", "http://schema.org/Optician" + "Optometric", "http://schema.org/Optometric" + "Order", "http://schema.org/Order" + "OrderAction", "http://schema.org/OrderAction" + "OrderCancelled", "http://schema.org/OrderCancelled" + "OrderDelivered", "http://schema.org/OrderDelivered" + "OrderInTransit", "http://schema.org/OrderInTransit" + "OrderItem", "http://schema.org/OrderItem" + "OrderPaymentDue", "http://schema.org/OrderPaymentDue" + "OrderPickupAvailable", "http://schema.org/OrderPickupAvailable" + "OrderProblem", "http://schema.org/OrderProblem" + "OrderProcessing", "http://schema.org/OrderProcessing" + "OrderReturned", "http://schema.org/OrderReturned" + "OrderStatus", "http://schema.org/OrderStatus" + "Organization", "http://schema.org/Organization" + "OrganizationRole", "http://schema.org/OrganizationRole" + "OrganizeAction", "http://schema.org/OrganizeAction" + "OriginalShippingFees", "http://schema.org/OriginalShippingFees" + "Osteopathic", "http://schema.org/Osteopathic" + "Otolaryngologic", "http://schema.org/Otolaryngologic" + "OutOfStock", "http://schema.org/OutOfStock" + "OutletStore", "http://schema.org/OutletStore" + "OverviewHealthAspect", "http://schema.org/OverviewHealthAspect" + "OwnershipInfo", "http://schema.org/OwnershipInfo" + "PET", "http://schema.org/PET" + "PaidLeave", "http://schema.org/PaidLeave" + "PaintAction", "http://schema.org/PaintAction" + "Painting", "http://schema.org/Painting" + "PalliativeProcedure", "http://schema.org/PalliativeProcedure" + "Paperback", "http://schema.org/Paperback" + "ParcelDelivery", "http://schema.org/ParcelDelivery" + "ParcelService", "http://schema.org/ParcelService" + "ParentAudience", "http://schema.org/ParentAudience" + "ParentalSupport", "http://schema.org/ParentalSupport" + "Park", "http://schema.org/Park" + "ParkingFacility", "http://schema.org/ParkingFacility" + "ParkingMap", "http://schema.org/ParkingMap" + "PartiallyInForce", "http://schema.org/PartiallyInForce" + "Pathology", "http://schema.org/Pathology" + "PathologyTest", "http://schema.org/PathologyTest" + "Patient", "http://schema.org/Patient" + "PatientExperienceHealthAspect", "http://schema.org/PatientExperienceHealthAspect" + "PawnShop", "http://schema.org/PawnShop" + "PayAction", "http://schema.org/PayAction" + "PaymentAutomaticallyApplied", "http://schema.org/PaymentAutomaticallyApplied" + "PaymentCard", "http://schema.org/PaymentCard" + "PaymentChargeSpecification", "http://schema.org/PaymentChargeSpecification" + "PaymentComplete", "http://schema.org/PaymentComplete" + "PaymentDeclined", "http://schema.org/PaymentDeclined" + "PaymentDue", "http://schema.org/PaymentDue" + "PaymentMethod", "http://schema.org/PaymentMethod" + "PaymentPastDue", "http://schema.org/PaymentPastDue" + "PaymentService", "http://schema.org/PaymentService" + "PaymentStatusType", "http://schema.org/PaymentStatusType" + "Pediatric", "http://schema.org/Pediatric" + "PeopleAudience", "http://schema.org/PeopleAudience" + "PercutaneousProcedure", "http://schema.org/PercutaneousProcedure" + "PerformAction", "http://schema.org/PerformAction" + "PerformanceRole", "http://schema.org/PerformanceRole" + "PerformingArtsTheater", "http://schema.org/PerformingArtsTheater" + "PerformingGroup", "http://schema.org/PerformingGroup" + "Periodical", "http://schema.org/Periodical" + "Permit", "http://schema.org/Permit" + "Person", "http://schema.org/Person" + "PetStore", "http://schema.org/PetStore" + "Pharmacy", "http://schema.org/Pharmacy" + "PharmacySpecialty", "http://schema.org/PharmacySpecialty" + "Photograph", "http://schema.org/Photograph" + "PhotographAction", "http://schema.org/PhotographAction" + "PhysicalActivity", "http://schema.org/PhysicalActivity" + "PhysicalActivityCategory", "http://schema.org/PhysicalActivityCategory" + "PhysicalExam", "http://schema.org/PhysicalExam" + "PhysicalTherapy", "http://schema.org/PhysicalTherapy" + "Physician", "http://schema.org/Physician" + "Physiotherapy", "http://schema.org/Physiotherapy" + "Place", "http://schema.org/Place" + "PlaceOfWorship", "http://schema.org/PlaceOfWorship" + "PlaceboControlledTrial", "http://schema.org/PlaceboControlledTrial" + "PlanAction", "http://schema.org/PlanAction" + "PlasticSurgery", "http://schema.org/PlasticSurgery" + "Play", "http://schema.org/Play" + "PlayAction", "http://schema.org/PlayAction" + "Playground", "http://schema.org/Playground" + "Plumber", "http://schema.org/Plumber" + "PodcastEpisode", "http://schema.org/PodcastEpisode" + "PodcastSeason", "http://schema.org/PodcastSeason" + "PodcastSeries", "http://schema.org/PodcastSeries" + "Podiatric", "http://schema.org/Podiatric" + "PoliceStation", "http://schema.org/PoliceStation" + "Pond", "http://schema.org/Pond" + "PostOffice", "http://schema.org/PostOffice" + "PostalAddress", "http://schema.org/PostalAddress" + "PostalCodeRangeSpecification", "http://schema.org/PostalCodeRangeSpecification" + "Poster", "http://schema.org/Poster" + "PotentialActionStatus", "http://schema.org/PotentialActionStatus" + "PreOrder", "http://schema.org/PreOrder" + "PreOrderAction", "http://schema.org/PreOrderAction" + "PreSale", "http://schema.org/PreSale" + "PrependAction", "http://schema.org/PrependAction" + "Preschool", "http://schema.org/Preschool" + "PrescriptionOnly", "http://schema.org/PrescriptionOnly" + "PresentationDigitalDocument", "http://schema.org/PresentationDigitalDocument" + "PreventionHealthAspect", "http://schema.org/PreventionHealthAspect" + "PreventionIndication", "http://schema.org/PreventionIndication" + "PriceSpecification", "http://schema.org/PriceSpecification" + "PrimaryCare", "http://schema.org/PrimaryCare" + "Prion", "http://schema.org/Prion" + "Product", "http://schema.org/Product" + "ProductCollection", "http://schema.org/ProductCollection" + "ProductGroup", "http://schema.org/ProductGroup" + "ProductModel", "http://schema.org/ProductModel" + "ProductReturnEnumeration", "http://schema.org/ProductReturnEnumeration" + "ProductReturnFiniteReturnWindow", "http://schema.org/ProductReturnFiniteReturnWindow" + "ProductReturnNotPermitted", "http://schema.org/ProductReturnNotPermitted" + "ProductReturnPolicy", "http://schema.org/ProductReturnPolicy" + "ProductReturnUnlimitedWindow", "http://schema.org/ProductReturnUnlimitedWindow" + "ProductReturnUnspecified", "http://schema.org/ProductReturnUnspecified" + "ProfessionalService", "http://schema.org/ProfessionalService" + "ProfilePage", "http://schema.org/ProfilePage" + "PrognosisHealthAspect", "http://schema.org/PrognosisHealthAspect" + "ProgramMembership", "http://schema.org/ProgramMembership" + "Project", "http://schema.org/Project" + "PronounceableText", "http://schema.org/PronounceableText" + "Property", "http://schema.org/Property" + "PropertyValue", "http://schema.org/PropertyValue" + "PropertyValueSpecification", "http://schema.org/PropertyValueSpecification" + "Protozoa", "http://schema.org/Protozoa" + "Psychiatric", "http://schema.org/Psychiatric" + "PsychologicalTreatment", "http://schema.org/PsychologicalTreatment" + "PublicHealth", "http://schema.org/PublicHealth" + "PublicHolidays", "http://schema.org/PublicHolidays" + "PublicSwimmingPool", "http://schema.org/PublicSwimmingPool" + "PublicToilet", "http://schema.org/PublicToilet" + "PublicationEvent", "http://schema.org/PublicationEvent" + "PublicationIssue", "http://schema.org/PublicationIssue" + "PublicationVolume", "http://schema.org/PublicationVolume" + "Pulmonary", "http://schema.org/Pulmonary" + "QAPage", "http://schema.org/QAPage" + "QualitativeValue", "http://schema.org/QualitativeValue" + "QuantitativeValue", "http://schema.org/QuantitativeValue" + "QuantitativeValueDistribution", "http://schema.org/QuantitativeValueDistribution" + "Quantity", "http://schema.org/Quantity" + "Question", "http://schema.org/Question" + "Quiz", "http://schema.org/Quiz" + "Quotation", "http://schema.org/Quotation" + "QuoteAction", "http://schema.org/QuoteAction" + "RVPark", "http://schema.org/RVPark" + "RadiationTherapy", "http://schema.org/RadiationTherapy" + "RadioBroadcastService", "http://schema.org/RadioBroadcastService" + "RadioChannel", "http://schema.org/RadioChannel" + "RadioClip", "http://schema.org/RadioClip" + "RadioEpisode", "http://schema.org/RadioEpisode" + "RadioSeason", "http://schema.org/RadioSeason" + "RadioSeries", "http://schema.org/RadioSeries" + "RadioStation", "http://schema.org/RadioStation" + "Radiography", "http://schema.org/Radiography" + "RandomizedTrial", "http://schema.org/RandomizedTrial" + "Rating", "http://schema.org/Rating" + "ReactAction", "http://schema.org/ReactAction" + "ReadAction", "http://schema.org/ReadAction" + "ReadPermission", "http://schema.org/ReadPermission" + "RealEstateAgent", "http://schema.org/RealEstateAgent" + "RealEstateListing", "http://schema.org/RealEstateListing" + "RearWheelDriveConfiguration", "http://schema.org/RearWheelDriveConfiguration" + "ReceiveAction", "http://schema.org/ReceiveAction" + "Recipe", "http://schema.org/Recipe" + "Recommendation", "http://schema.org/Recommendation" + "RecommendedDoseSchedule", "http://schema.org/RecommendedDoseSchedule" + "Recruiting", "http://schema.org/Recruiting" + "RecyclingCenter", "http://schema.org/RecyclingCenter" + "RefundTypeEnumeration", "http://schema.org/RefundTypeEnumeration" + "RefurbishedCondition", "http://schema.org/RefurbishedCondition" + "RegisterAction", "http://schema.org/RegisterAction" + "Registry", "http://schema.org/Registry" + "ReimbursementCap", "http://schema.org/ReimbursementCap" + "RejectAction", "http://schema.org/RejectAction" + "RelatedTopicsHealthAspect", "http://schema.org/RelatedTopicsHealthAspect" + "RemixAlbum", "http://schema.org/RemixAlbum" + "Renal", "http://schema.org/Renal" + "RentAction", "http://schema.org/RentAction" + "RentalCarReservation", "http://schema.org/RentalCarReservation" + "RentalVehicleUsage", "http://schema.org/RentalVehicleUsage" + "RepaymentSpecification", "http://schema.org/RepaymentSpecification" + "ReplaceAction", "http://schema.org/ReplaceAction" + "ReplyAction", "http://schema.org/ReplyAction" + "Report", "http://schema.org/Report" + "ReportageNewsArticle", "http://schema.org/ReportageNewsArticle" + "ReportedDoseSchedule", "http://schema.org/ReportedDoseSchedule" + "ResearchProject", "http://schema.org/ResearchProject" + "Researcher", "http://schema.org/Researcher" + "Reservation", "http://schema.org/Reservation" + "ReservationCancelled", "http://schema.org/ReservationCancelled" + "ReservationConfirmed", "http://schema.org/ReservationConfirmed" + "ReservationHold", "http://schema.org/ReservationHold" + "ReservationPackage", "http://schema.org/ReservationPackage" + "ReservationPending", "http://schema.org/ReservationPending" + "ReservationStatusType", "http://schema.org/ReservationStatusType" + "ReserveAction", "http://schema.org/ReserveAction" + "Reservoir", "http://schema.org/Reservoir" + "Residence", "http://schema.org/Residence" + "Resort", "http://schema.org/Resort" + "RespiratoryTherapy", "http://schema.org/RespiratoryTherapy" + "Restaurant", "http://schema.org/Restaurant" + "RestockingFees", "http://schema.org/RestockingFees" + "RestrictedDiet", "http://schema.org/RestrictedDiet" + "ResultsAvailable", "http://schema.org/ResultsAvailable" + "ResultsNotAvailable", "http://schema.org/ResultsNotAvailable" + "ResumeAction", "http://schema.org/ResumeAction" + "Retail", "http://schema.org/Retail" + "ReturnAction", "http://schema.org/ReturnAction" + "ReturnFeesEnumeration", "http://schema.org/ReturnFeesEnumeration" + "ReturnShippingFees", "http://schema.org/ReturnShippingFees" + "Review", "http://schema.org/Review" + "ReviewAction", "http://schema.org/ReviewAction" + "ReviewNewsArticle", "http://schema.org/ReviewNewsArticle" + "Rheumatologic", "http://schema.org/Rheumatologic" + "RightHandDriving", "http://schema.org/RightHandDriving" + "RisksOrComplicationsHealthAspect", "http://schema.org/RisksOrComplicationsHealthAspect" + "RiverBodyOfWater", "http://schema.org/RiverBodyOfWater" + "Role", "http://schema.org/Role" + "RoofingContractor", "http://schema.org/RoofingContractor" + "Room", "http://schema.org/Room" + "RsvpAction", "http://schema.org/RsvpAction" + "RsvpResponseMaybe", "http://schema.org/RsvpResponseMaybe" + "RsvpResponseNo", "http://schema.org/RsvpResponseNo" + "RsvpResponseType", "http://schema.org/RsvpResponseType" + "RsvpResponseYes", "http://schema.org/RsvpResponseYes" + "SaleEvent", "http://schema.org/SaleEvent" + "SatiricalArticle", "http://schema.org/SatiricalArticle" + "Saturday", "http://schema.org/Saturday" + "Schedule", "http://schema.org/Schedule" + "ScheduleAction", "http://schema.org/ScheduleAction" + "ScholarlyArticle", "http://schema.org/ScholarlyArticle" + "School", "http://schema.org/School" + "SchoolDistrict", "http://schema.org/SchoolDistrict" + "ScreeningEvent", "http://schema.org/ScreeningEvent" + "ScreeningHealthAspect", "http://schema.org/ScreeningHealthAspect" + "Sculpture", "http://schema.org/Sculpture" + "SeaBodyOfWater", "http://schema.org/SeaBodyOfWater" + "SearchAction", "http://schema.org/SearchAction" + "SearchResultsPage", "http://schema.org/SearchResultsPage" + "Season", "http://schema.org/Season" + "Seat", "http://schema.org/Seat" + "SeatingMap", "http://schema.org/SeatingMap" + "SeeDoctorHealthAspect", "http://schema.org/SeeDoctorHealthAspect" + "SelfCareHealthAspect", "http://schema.org/SelfCareHealthAspect" + "SelfStorage", "http://schema.org/SelfStorage" + "SellAction", "http://schema.org/SellAction" + "SendAction", "http://schema.org/SendAction" + "Series", "http://schema.org/Series" + "Service", "http://schema.org/Service" + "ServiceChannel", "http://schema.org/ServiceChannel" + "ShareAction", "http://schema.org/ShareAction" + "SheetMusic", "http://schema.org/SheetMusic" + "ShippingDeliveryTime", "http://schema.org/ShippingDeliveryTime" + "ShippingRateSettings", "http://schema.org/ShippingRateSettings" + "ShoeStore", "http://schema.org/ShoeStore" + "ShoppingCenter", "http://schema.org/ShoppingCenter" + "ShortStory", "http://schema.org/ShortStory" + "SideEffectsHealthAspect", "http://schema.org/SideEffectsHealthAspect" + "SingleBlindedTrial", "http://schema.org/SingleBlindedTrial" + "SingleCenterTrial", "http://schema.org/SingleCenterTrial" + "SingleFamilyResidence", "http://schema.org/SingleFamilyResidence" + "SinglePlayer", "http://schema.org/SinglePlayer" + "SingleRelease", "http://schema.org/SingleRelease" + "SiteNavigationElement", "http://schema.org/SiteNavigationElement" + "SkiResort", "http://schema.org/SkiResort" + "Skin", "http://schema.org/Skin" + "SocialEvent", "http://schema.org/SocialEvent" + "SocialMediaPosting", "http://schema.org/SocialMediaPosting" + "SoftwareApplication", "http://schema.org/SoftwareApplication" + "SoftwareSourceCode", "http://schema.org/SoftwareSourceCode" + "SoldOut", "http://schema.org/SoldOut" + "SomeProducts", "http://schema.org/SomeProducts" + "SoundtrackAlbum", "http://schema.org/SoundtrackAlbum" + "SpeakableSpecification", "http://schema.org/SpeakableSpecification" + "SpecialAnnouncement", "http://schema.org/SpecialAnnouncement" + "Specialty", "http://schema.org/Specialty" + "SpeechPathology", "http://schema.org/SpeechPathology" + "SpokenWordAlbum", "http://schema.org/SpokenWordAlbum" + "SportingGoodsStore", "http://schema.org/SportingGoodsStore" + "SportsActivityLocation", "http://schema.org/SportsActivityLocation" + "SportsClub", "http://schema.org/SportsClub" + "SportsEvent", "http://schema.org/SportsEvent" + "SportsOrganization", "http://schema.org/SportsOrganization" + "SportsTeam", "http://schema.org/SportsTeam" + "SpreadsheetDigitalDocument", "http://schema.org/SpreadsheetDigitalDocument" + "StadiumOrArena", "http://schema.org/StadiumOrArena" + "StagesHealthAspect", "http://schema.org/StagesHealthAspect" + "State", "http://schema.org/State" + "StatisticalPopulation", "http://schema.org/StatisticalPopulation" + "StatusEnumeration", "http://schema.org/StatusEnumeration" + "SteeringPositionValue", "http://schema.org/SteeringPositionValue" + "Store", "http://schema.org/Store" + "StoreCreditRefund", "http://schema.org/StoreCreditRefund" + "StrengthTraining", "http://schema.org/StrengthTraining" + "StructuredValue", "http://schema.org/StructuredValue" + "StudioAlbum", "http://schema.org/StudioAlbum" + "StupidType", "http://schema.org/StupidType" + "SubscribeAction", "http://schema.org/SubscribeAction" + "Substance", "http://schema.org/Substance" + "SubwayStation", "http://schema.org/SubwayStation" + "Suite", "http://schema.org/Suite" + "Sunday", "http://schema.org/Sunday" + "SuperficialAnatomy", "http://schema.org/SuperficialAnatomy" + "Surgical", "http://schema.org/Surgical" + "SurgicalProcedure", "http://schema.org/SurgicalProcedure" + "SuspendAction", "http://schema.org/SuspendAction" + "Suspended", "http://schema.org/Suspended" + "SymptomsHealthAspect", "http://schema.org/SymptomsHealthAspect" + "Synagogue", "http://schema.org/Synagogue" + "TVClip", "http://schema.org/TVClip" + "TVEpisode", "http://schema.org/TVEpisode" + "TVSeason", "http://schema.org/TVSeason" + "TVSeries", "http://schema.org/TVSeries" + "Table", "http://schema.org/Table" + "TakeAction", "http://schema.org/TakeAction" + "TattooParlor", "http://schema.org/TattooParlor" + "Taxi", "http://schema.org/Taxi" + "TaxiReservation", "http://schema.org/TaxiReservation" + "TaxiService", "http://schema.org/TaxiService" + "TaxiStand", "http://schema.org/TaxiStand" + "TaxiVehicleUsage", "http://schema.org/TaxiVehicleUsage" + "TechArticle", "http://schema.org/TechArticle" + "TelevisionChannel", "http://schema.org/TelevisionChannel" + "TelevisionStation", "http://schema.org/TelevisionStation" + "TennisComplex", "http://schema.org/TennisComplex" + "Terminated", "http://schema.org/Terminated" + "Text", "http://schema.org/Text" + "TextDigitalDocument", "http://schema.org/TextDigitalDocument" + "TheaterEvent", "http://schema.org/TheaterEvent" + "TheaterGroup", "http://schema.org/TheaterGroup" + "Therapeutic", "http://schema.org/Therapeutic" + "TherapeuticProcedure", "http://schema.org/TherapeuticProcedure" + "Thesis", "http://schema.org/Thesis" + "Thing", "http://schema.org/Thing" + "Throat", "http://schema.org/Throat" + "Thursday", "http://schema.org/Thursday" + "Ticket", "http://schema.org/Ticket" + "TieAction", "http://schema.org/TieAction" + "Time", "http://schema.org/Time" + "TipAction", "http://schema.org/TipAction" + "TireShop", "http://schema.org/TireShop" + "TollFree", "http://schema.org/TollFree" + "TouristAttraction", "http://schema.org/TouristAttraction" + "TouristDestination", "http://schema.org/TouristDestination" + "TouristInformationCenter", "http://schema.org/TouristInformationCenter" + "TouristTrip", "http://schema.org/TouristTrip" + "Toxicologic", "http://schema.org/Toxicologic" + "ToyStore", "http://schema.org/ToyStore" + "TrackAction", "http://schema.org/TrackAction" + "TradeAction", "http://schema.org/TradeAction" + "TraditionalChinese", "http://schema.org/TraditionalChinese" + "TrainReservation", "http://schema.org/TrainReservation" + "TrainStation", "http://schema.org/TrainStation" + "TrainTrip", "http://schema.org/TrainTrip" + "TransferAction", "http://schema.org/TransferAction" + "TransitMap", "http://schema.org/TransitMap" + "TravelAction", "http://schema.org/TravelAction" + "TravelAgency", "http://schema.org/TravelAgency" + "TreatmentIndication", "http://schema.org/TreatmentIndication" + "TreatmentsHealthAspect", "http://schema.org/TreatmentsHealthAspect" + "Trip", "http://schema.org/Trip" + "TripleBlindedTrial", "http://schema.org/TripleBlindedTrial" + "True", "http://schema.org/True" + "Tuesday", "http://schema.org/Tuesday" + "TypeAndQuantityNode", "http://schema.org/TypeAndQuantityNode" + "TypesHealthAspect", "http://schema.org/TypesHealthAspect" + "UKNonprofitType", "http://schema.org/UKNonprofitType" + "UKTrust", "http://schema.org/UKTrust" + "URL", "http://schema.org/URL" + "USNonprofitType", "http://schema.org/USNonprofitType" + "Ultrasound", "http://schema.org/Ultrasound" + "UnRegisterAction", "http://schema.org/UnRegisterAction" + "UnemploymentSupport", "http://schema.org/UnemploymentSupport" + "UnincorporatedAssociationCharity", "http://schema.org/UnincorporatedAssociationCharity" + "UnitPriceSpecification", "http://schema.org/UnitPriceSpecification" + "UnofficialLegalValue", "http://schema.org/UnofficialLegalValue" + "UpdateAction", "http://schema.org/UpdateAction" + "Urologic", "http://schema.org/Urologic" + "UsageOrScheduleHealthAspect", "http://schema.org/UsageOrScheduleHealthAspect" + "UseAction", "http://schema.org/UseAction" + "UsedCondition", "http://schema.org/UsedCondition" + "UserBlocks", "http://schema.org/UserBlocks" + "UserCheckins", "http://schema.org/UserCheckins" + "UserComments", "http://schema.org/UserComments" + "UserDownloads", "http://schema.org/UserDownloads" + "UserInteraction", "http://schema.org/UserInteraction" + "UserLikes", "http://schema.org/UserLikes" + "UserPageVisits", "http://schema.org/UserPageVisits" + "UserPlays", "http://schema.org/UserPlays" + "UserPlusOnes", "http://schema.org/UserPlusOnes" + "UserReview", "http://schema.org/UserReview" + "UserTweets", "http://schema.org/UserTweets" + "VeganDiet", "http://schema.org/VeganDiet" + "VegetarianDiet", "http://schema.org/VegetarianDiet" + "Vehicle", "http://schema.org/Vehicle" + "Vein", "http://schema.org/Vein" + "VenueMap", "http://schema.org/VenueMap" + "Vessel", "http://schema.org/Vessel" + "VeterinaryCare", "http://schema.org/VeterinaryCare" + "VideoGallery", "http://schema.org/VideoGallery" + "VideoGame", "http://schema.org/VideoGame" + "VideoGameClip", "http://schema.org/VideoGameClip" + "VideoGameSeries", "http://schema.org/VideoGameSeries" + "VideoObject", "http://schema.org/VideoObject" + "ViewAction", "http://schema.org/ViewAction" + "VinylFormat", "http://schema.org/VinylFormat" + "VirtualLocation", "http://schema.org/VirtualLocation" + "Virus", "http://schema.org/Virus" + "VisualArtsEvent", "http://schema.org/VisualArtsEvent" + "VisualArtwork", "http://schema.org/VisualArtwork" + "VitalSign", "http://schema.org/VitalSign" + "Volcano", "http://schema.org/Volcano" + "VoteAction", "http://schema.org/VoteAction" + "WPAdBlock", "http://schema.org/WPAdBlock" + "WPFooter", "http://schema.org/WPFooter" + "WPHeader", "http://schema.org/WPHeader" + "WPSideBar", "http://schema.org/WPSideBar" + "WantAction", "http://schema.org/WantAction" + "WarrantyPromise", "http://schema.org/WarrantyPromise" + "WarrantyScope", "http://schema.org/WarrantyScope" + "WatchAction", "http://schema.org/WatchAction" + "Waterfall", "http://schema.org/Waterfall" + "WearAction", "http://schema.org/WearAction" + "WebAPI", "http://schema.org/WebAPI" + "WebApplication", "http://schema.org/WebApplication" + "WebContent", "http://schema.org/WebContent" + "WebPage", "http://schema.org/WebPage" + "WebPageElement", "http://schema.org/WebPageElement" + "WebSite", "http://schema.org/WebSite" + "Wednesday", "http://schema.org/Wednesday" + "WesternConventional", "http://schema.org/WesternConventional" + "Wholesale", "http://schema.org/Wholesale" + "WholesaleStore", "http://schema.org/WholesaleStore" + "WinAction", "http://schema.org/WinAction" + "Winery", "http://schema.org/Winery" + "Withdrawn", "http://schema.org/Withdrawn" + "WorkBasedProgram", "http://schema.org/WorkBasedProgram" + "WorkersUnion", "http://schema.org/WorkersUnion" + "WriteAction", "http://schema.org/WriteAction" + "WritePermission", "http://schema.org/WritePermission" + "XPathType", "http://schema.org/XPathType" + "XRay", "http://schema.org/XRay" + "ZoneBoardingPolicy", "http://schema.org/ZoneBoardingPolicy" + "Zoo", "http://schema.org/Zoo" + "about", "http://schema.org/about" + "abridged", "http://schema.org/abridged" + "abstract", "http://schema.org/abstract" + "accelerationTime", "http://schema.org/accelerationTime" + "acceptedAnswer", "http://schema.org/acceptedAnswer" + "acceptedOffer", "http://schema.org/acceptedOffer" + "acceptedPaymentMethod", "http://schema.org/acceptedPaymentMethod" + "acceptsReservations", "http://schema.org/acceptsReservations" + "accessCode", "http://schema.org/accessCode" + "accessMode", "http://schema.org/accessMode" + "accessModeSufficient", "http://schema.org/accessModeSufficient" + "accessibilityAPI", "http://schema.org/accessibilityAPI" + "accessibilityControl", "http://schema.org/accessibilityControl" + "accessibilityFeature", "http://schema.org/accessibilityFeature" + "accessibilityHazard", "http://schema.org/accessibilityHazard" + "accessibilitySummary", "http://schema.org/accessibilitySummary" + "accommodationCategory", "http://schema.org/accommodationCategory" + "accommodationFloorPlan", "http://schema.org/accommodationFloorPlan" + "accountId", "http://schema.org/accountId" + "accountMinimumInflow", "http://schema.org/accountMinimumInflow" + "accountOverdraftLimit", "http://schema.org/accountOverdraftLimit" + "accountablePerson", "http://schema.org/accountablePerson" + "acquireLicensePage", "http://schema.org/acquireLicensePage" + "acquiredFrom", "http://schema.org/acquiredFrom" + "acrissCode", "http://schema.org/acrissCode" + "actionAccessibilityRequirement", "http://schema.org/actionAccessibilityRequirement" + "actionApplication", "http://schema.org/actionApplication" + "actionOption", "http://schema.org/actionOption" + "actionPlatform", "http://schema.org/actionPlatform" + "actionStatus", "http://schema.org/actionStatus" + "actionableFeedbackPolicy", "http://schema.org/actionableFeedbackPolicy" + "activeIngredient", "http://schema.org/activeIngredient" + "activityDuration", "http://schema.org/activityDuration" + "activityFrequency", "http://schema.org/activityFrequency" + "actor", "http://schema.org/actor" + "actors", "http://schema.org/actors" + "addOn", "http://schema.org/addOn" + "additionalName", "http://schema.org/additionalName" + "additionalNumberOfGuests", "http://schema.org/additionalNumberOfGuests" + "additionalProperty", "http://schema.org/additionalProperty" + "additionalType", "http://schema.org/additionalType" + "additionalVariable", "http://schema.org/additionalVariable" + "address", "http://schema.org/address" + "addressCountry", "http://schema.org/addressCountry" + "addressLocality", "http://schema.org/addressLocality" + "addressRegion", "http://schema.org/addressRegion" + "administrationRoute", "http://schema.org/administrationRoute" + "advanceBookingRequirement", "http://schema.org/advanceBookingRequirement" + "adverseOutcome", "http://schema.org/adverseOutcome" + "affectedBy", "http://schema.org/affectedBy" + "affiliation", "http://schema.org/affiliation" + "afterMedia", "http://schema.org/afterMedia" + "agent", "http://schema.org/agent" + "aggregateRating", "http://schema.org/aggregateRating" + "aircraft", "http://schema.org/aircraft" + "album", "http://schema.org/album" + "albumProductionType", "http://schema.org/albumProductionType" + "albumRelease", "http://schema.org/albumRelease" + "albumReleaseType", "http://schema.org/albumReleaseType" + "albums", "http://schema.org/albums" + "alcoholWarning", "http://schema.org/alcoholWarning" + "algorithm", "http://schema.org/algorithm" + "alignmentType", "http://schema.org/alignmentType" + "alternateName", "http://schema.org/alternateName" + "alternativeHeadline", "http://schema.org/alternativeHeadline" + "alumni", "http://schema.org/alumni" + "alumniOf", "http://schema.org/alumniOf" + "amenityFeature", "http://schema.org/amenityFeature" + "amount", "http://schema.org/amount" + "amountOfThisGood", "http://schema.org/amountOfThisGood" + "announcementLocation", "http://schema.org/announcementLocation" + "annualPercentageRate", "http://schema.org/annualPercentageRate" + "answerCount", "http://schema.org/answerCount" + "answerExplanation", "http://schema.org/answerExplanation" + "antagonist", "http://schema.org/antagonist" + "appearance", "http://schema.org/appearance" + "applicableLocation", "http://schema.org/applicableLocation" + "applicantLocationRequirements", "http://schema.org/applicantLocationRequirements" + "application", "http://schema.org/application" + "applicationCategory", "http://schema.org/applicationCategory" + "applicationContact", "http://schema.org/applicationContact" + "applicationDeadline", "http://schema.org/applicationDeadline" + "applicationStartDate", "http://schema.org/applicationStartDate" + "applicationSubCategory", "http://schema.org/applicationSubCategory" + "applicationSuite", "http://schema.org/applicationSuite" + "appliesToDeliveryMethod", "http://schema.org/appliesToDeliveryMethod" + "appliesToPaymentMethod", "http://schema.org/appliesToPaymentMethod" + "archiveHeld", "http://schema.org/archiveHeld" + "area", "http://schema.org/area" + "areaServed", "http://schema.org/areaServed" + "arrivalAirport", "http://schema.org/arrivalAirport" + "arrivalBoatTerminal", "http://schema.org/arrivalBoatTerminal" + "arrivalBusStop", "http://schema.org/arrivalBusStop" + "arrivalGate", "http://schema.org/arrivalGate" + "arrivalPlatform", "http://schema.org/arrivalPlatform" + "arrivalStation", "http://schema.org/arrivalStation" + "arrivalTerminal", "http://schema.org/arrivalTerminal" + "arrivalTime", "http://schema.org/arrivalTime" + "artEdition", "http://schema.org/artEdition" + "artMedium", "http://schema.org/artMedium" + "arterialBranch", "http://schema.org/arterialBranch" + "artform", "http://schema.org/artform" + "articleBody", "http://schema.org/articleBody" + "articleSection", "http://schema.org/articleSection" + "artist", "http://schema.org/artist" + "artworkSurface", "http://schema.org/artworkSurface" + "aspect", "http://schema.org/aspect" + "assembly", "http://schema.org/assembly" + "assemblyVersion", "http://schema.org/assemblyVersion" + "assesses", "http://schema.org/assesses" + "associatedAnatomy", "http://schema.org/associatedAnatomy" + "associatedArticle", "http://schema.org/associatedArticle" + "associatedMedia", "http://schema.org/associatedMedia" + "associatedPathophysiology", "http://schema.org/associatedPathophysiology" + "athlete", "http://schema.org/athlete" + "attendee", "http://schema.org/attendee" + "attendees", "http://schema.org/attendees" + "audience", "http://schema.org/audience" + "audienceType", "http://schema.org/audienceType" + "audio", "http://schema.org/audio" + "authenticator", "http://schema.org/authenticator" + "author", "http://schema.org/author" + "availability", "http://schema.org/availability" + "availabilityEnds", "http://schema.org/availabilityEnds" + "availabilityStarts", "http://schema.org/availabilityStarts" + "availableAtOrFrom", "http://schema.org/availableAtOrFrom" + "availableChannel", "http://schema.org/availableChannel" + "availableDeliveryMethod", "http://schema.org/availableDeliveryMethod" + "availableFrom", "http://schema.org/availableFrom" + "availableIn", "http://schema.org/availableIn" + "availableLanguage", "http://schema.org/availableLanguage" + "availableOnDevice", "http://schema.org/availableOnDevice" + "availableService", "http://schema.org/availableService" + "availableStrength", "http://schema.org/availableStrength" + "availableTest", "http://schema.org/availableTest" + "availableThrough", "http://schema.org/availableThrough" + "award", "http://schema.org/award" + "awards", "http://schema.org/awards" + "awayTeam", "http://schema.org/awayTeam" + "backstory", "http://schema.org/backstory" + "bankAccountType", "http://schema.org/bankAccountType" + "baseSalary", "http://schema.org/baseSalary" + "bccRecipient", "http://schema.org/bccRecipient" + "bed", "http://schema.org/bed" + "beforeMedia", "http://schema.org/beforeMedia" + "beneficiaryBank", "http://schema.org/beneficiaryBank" + "benefits", "http://schema.org/benefits" + "benefitsSummaryUrl", "http://schema.org/benefitsSummaryUrl" + "bestRating", "http://schema.org/bestRating" + "billingAddress", "http://schema.org/billingAddress" + "billingIncrement", "http://schema.org/billingIncrement" + "billingPeriod", "http://schema.org/billingPeriod" + "biomechnicalClass", "http://schema.org/biomechnicalClass" + "birthDate", "http://schema.org/birthDate" + "birthPlace", "http://schema.org/birthPlace" + "bitrate", "http://schema.org/bitrate" + "blogPost", "http://schema.org/blogPost" + "blogPosts", "http://schema.org/blogPosts" + "bloodSupply", "http://schema.org/bloodSupply" + "boardingGroup", "http://schema.org/boardingGroup" + "boardingPolicy", "http://schema.org/boardingPolicy" + "bodyLocation", "http://schema.org/bodyLocation" + "bodyType", "http://schema.org/bodyType" + "bookEdition", "http://schema.org/bookEdition" + "bookFormat", "http://schema.org/bookFormat" + "bookingAgent", "http://schema.org/bookingAgent" + "bookingTime", "http://schema.org/bookingTime" + "borrower", "http://schema.org/borrower" + "box", "http://schema.org/box" + "branch", "http://schema.org/branch" + "branchCode", "http://schema.org/branchCode" + "branchOf", "http://schema.org/branchOf" + "brand", "http://schema.org/brand" + "breadcrumb", "http://schema.org/breadcrumb" + "breastfeedingWarning", "http://schema.org/breastfeedingWarning" + "broadcastAffiliateOf", "http://schema.org/broadcastAffiliateOf" + "broadcastChannelId", "http://schema.org/broadcastChannelId" + "broadcastDisplayName", "http://schema.org/broadcastDisplayName" + "broadcastFrequency", "http://schema.org/broadcastFrequency" + "broadcastFrequencyValue", "http://schema.org/broadcastFrequencyValue" + "broadcastOfEvent", "http://schema.org/broadcastOfEvent" + "broadcastServiceTier", "http://schema.org/broadcastServiceTier" + "broadcastSignalModulation", "http://schema.org/broadcastSignalModulation" + "broadcastSubChannel", "http://schema.org/broadcastSubChannel" + "broadcastTimezone", "http://schema.org/broadcastTimezone" + "broadcaster", "http://schema.org/broadcaster" + "broker", "http://schema.org/broker" + "browserRequirements", "http://schema.org/browserRequirements" + "busName", "http://schema.org/busName" + "busNumber", "http://schema.org/busNumber" + "businessDays", "http://schema.org/businessDays" + "businessFunction", "http://schema.org/businessFunction" + "buyer", "http://schema.org/buyer" + "byArtist", "http://schema.org/byArtist" + "byDay", "http://schema.org/byDay" + "byMonth", "http://schema.org/byMonth" + "byMonthDay", "http://schema.org/byMonthDay" + "byMonthWeek", "http://schema.org/byMonthWeek" + "callSign", "http://schema.org/callSign" + "calories", "http://schema.org/calories" + "candidate", "http://schema.org/candidate" + "caption", "http://schema.org/caption" + "carbohydrateContent", "http://schema.org/carbohydrateContent" + "cargoVolume", "http://schema.org/cargoVolume" + "carrier", "http://schema.org/carrier" + "carrierRequirements", "http://schema.org/carrierRequirements" + "cashBack", "http://schema.org/cashBack" + "catalog", "http://schema.org/catalog" + "catalogNumber", "http://schema.org/catalogNumber" + "category", "http://schema.org/category" + "causeOf", "http://schema.org/causeOf" + "ccRecipient", "http://schema.org/ccRecipient" + "character", "http://schema.org/character" + "characterAttribute", "http://schema.org/characterAttribute" + "characterName", "http://schema.org/characterName" + "cheatCode", "http://schema.org/cheatCode" + "checkinTime", "http://schema.org/checkinTime" + "checkoutTime", "http://schema.org/checkoutTime" + "childMaxAge", "http://schema.org/childMaxAge" + "childMinAge", "http://schema.org/childMinAge" + "children", "http://schema.org/children" + "cholesterolContent", "http://schema.org/cholesterolContent" + "circle", "http://schema.org/circle" + "citation", "http://schema.org/citation" + "claimReviewed", "http://schema.org/claimReviewed" + "clincalPharmacology", "http://schema.org/clincalPharmacology" + "clinicalPharmacology", "http://schema.org/clinicalPharmacology" + "clipNumber", "http://schema.org/clipNumber" + "closes", "http://schema.org/closes" + "coach", "http://schema.org/coach" + "code", "http://schema.org/code" + "codeRepository", "http://schema.org/codeRepository" + "codeSampleType", "http://schema.org/codeSampleType" + "codeValue", "http://schema.org/codeValue" + "codingSystem", "http://schema.org/codingSystem" + "colleague", "http://schema.org/colleague" + "colleagues", "http://schema.org/colleagues" + "collection", "http://schema.org/collection" + "collectionSize", "http://schema.org/collectionSize" + "color", "http://schema.org/color" + "colorist", "http://schema.org/colorist" + "comment", "http://schema.org/comment" + "commentCount", "http://schema.org/commentCount" + "commentText", "http://schema.org/commentText" + "commentTime", "http://schema.org/commentTime" + "competencyRequired", "http://schema.org/competencyRequired" + "competitor", "http://schema.org/competitor" + "composer", "http://schema.org/composer" + "comprisedOf", "http://schema.org/comprisedOf" + "conditionsOfAccess", "http://schema.org/conditionsOfAccess" + "confirmationNumber", "http://schema.org/confirmationNumber" + "connectedTo", "http://schema.org/connectedTo" + "constrainingProperty", "http://schema.org/constrainingProperty" + "contactOption", "http://schema.org/contactOption" + "contactPoint", "http://schema.org/contactPoint" + "contactPoints", "http://schema.org/contactPoints" + "contactType", "http://schema.org/contactType" + "contactlessPayment", "http://schema.org/contactlessPayment" + "containedIn", "http://schema.org/containedIn" + "containedInPlace", "http://schema.org/containedInPlace" + "containsPlace", "http://schema.org/containsPlace" + "containsSeason", "http://schema.org/containsSeason" + "contentLocation", "http://schema.org/contentLocation" + "contentRating", "http://schema.org/contentRating" + "contentReferenceTime", "http://schema.org/contentReferenceTime" + "contentSize", "http://schema.org/contentSize" + "contentType", "http://schema.org/contentType" + "contentUrl", "http://schema.org/contentUrl" + "contraindication", "http://schema.org/contraindication" + "contributor", "http://schema.org/contributor" + "cookTime", "http://schema.org/cookTime" + "cookingMethod", "http://schema.org/cookingMethod" + "copyrightHolder", "http://schema.org/copyrightHolder" + "copyrightYear", "http://schema.org/copyrightYear" + "correction", "http://schema.org/correction" + "correctionsPolicy", "http://schema.org/correctionsPolicy" + "costCategory", "http://schema.org/costCategory" + "costCurrency", "http://schema.org/costCurrency" + "costOrigin", "http://schema.org/costOrigin" + "costPerUnit", "http://schema.org/costPerUnit" + "countriesNotSupported", "http://schema.org/countriesNotSupported" + "countriesSupported", "http://schema.org/countriesSupported" + "countryOfOrigin", "http://schema.org/countryOfOrigin" + "course", "http://schema.org/course" + "courseCode", "http://schema.org/courseCode" + "courseMode", "http://schema.org/courseMode" + "coursePrerequisites", "http://schema.org/coursePrerequisites" + "courseWorkload", "http://schema.org/courseWorkload" + "coverageEndTime", "http://schema.org/coverageEndTime" + "coverageStartTime", "http://schema.org/coverageStartTime" + "creativeWorkStatus", "http://schema.org/creativeWorkStatus" + "creator", "http://schema.org/creator" + "credentialCategory", "http://schema.org/credentialCategory" + "creditedTo", "http://schema.org/creditedTo" + "cssSelector", "http://schema.org/cssSelector" + "currenciesAccepted", "http://schema.org/currenciesAccepted" + "currency", "http://schema.org/currency" + "currentExchangeRate", "http://schema.org/currentExchangeRate" + "customer", "http://schema.org/customer" + "cutoffTime", "http://schema.org/cutoffTime" + "cvdCollectionDate", "http://schema.org/cvdCollectionDate" + "cvdFacilityCounty", "http://schema.org/cvdFacilityCounty" + "cvdFacilityId", "http://schema.org/cvdFacilityId" + "cvdNumBeds", "http://schema.org/cvdNumBeds" + "cvdNumBedsOcc", "http://schema.org/cvdNumBedsOcc" + "cvdNumC19Died", "http://schema.org/cvdNumC19Died" + "cvdNumC19HOPats", "http://schema.org/cvdNumC19HOPats" + "cvdNumC19HospPats", "http://schema.org/cvdNumC19HospPats" + "cvdNumC19MechVentPats", "http://schema.org/cvdNumC19MechVentPats" + "cvdNumC19OFMechVentPats", "http://schema.org/cvdNumC19OFMechVentPats" + "cvdNumC19OverflowPats", "http://schema.org/cvdNumC19OverflowPats" + "cvdNumICUBeds", "http://schema.org/cvdNumICUBeds" + "cvdNumICUBedsOcc", "http://schema.org/cvdNumICUBedsOcc" + "cvdNumTotBeds", "http://schema.org/cvdNumTotBeds" + "cvdNumVent", "http://schema.org/cvdNumVent" + "cvdNumVentUse", "http://schema.org/cvdNumVentUse" + "dataFeedElement", "http://schema.org/dataFeedElement" + "dataset", "http://schema.org/dataset" + "datasetTimeInterval", "http://schema.org/datasetTimeInterval" + "dateCreated", "http://schema.org/dateCreated" + "dateDeleted", "http://schema.org/dateDeleted" + "dateIssued", "http://schema.org/dateIssued" + "dateModified", "http://schema.org/dateModified" + "datePosted", "http://schema.org/datePosted" + "datePublished", "http://schema.org/datePublished" + "dateRead", "http://schema.org/dateRead" + "dateReceived", "http://schema.org/dateReceived" + "dateSent", "http://schema.org/dateSent" + "dateVehicleFirstRegistered", "http://schema.org/dateVehicleFirstRegistered" + "dateline", "http://schema.org/dateline" + "dayOfWeek", "http://schema.org/dayOfWeek" + "deathDate", "http://schema.org/deathDate" + "deathPlace", "http://schema.org/deathPlace" + "defaultValue", "http://schema.org/defaultValue" + "deliveryAddress", "http://schema.org/deliveryAddress" + "deliveryLeadTime", "http://schema.org/deliveryLeadTime" + "deliveryMethod", "http://schema.org/deliveryMethod" + "deliveryStatus", "http://schema.org/deliveryStatus" + "deliveryTime", "http://schema.org/deliveryTime" + "department", "http://schema.org/department" + "departureAirport", "http://schema.org/departureAirport" + "departureBoatTerminal", "http://schema.org/departureBoatTerminal" + "departureBusStop", "http://schema.org/departureBusStop" + "departureGate", "http://schema.org/departureGate" + "departurePlatform", "http://schema.org/departurePlatform" + "departureStation", "http://schema.org/departureStation" + "departureTerminal", "http://schema.org/departureTerminal" + "departureTime", "http://schema.org/departureTime" + "dependencies", "http://schema.org/dependencies" + "depth", "http://schema.org/depth" + "description", "http://schema.org/description" + "device", "http://schema.org/device" + "diagnosis", "http://schema.org/diagnosis" + "diagram", "http://schema.org/diagram" + "diet", "http://schema.org/diet" + "dietFeatures", "http://schema.org/dietFeatures" + "differentialDiagnosis", "http://schema.org/differentialDiagnosis" + "director", "http://schema.org/director" + "directors", "http://schema.org/directors" + "disambiguatingDescription", "http://schema.org/disambiguatingDescription" + "discount", "http://schema.org/discount" + "discountCode", "http://schema.org/discountCode" + "discountCurrency", "http://schema.org/discountCurrency" + "discusses", "http://schema.org/discusses" + "discussionUrl", "http://schema.org/discussionUrl" + "diseasePreventionInfo", "http://schema.org/diseasePreventionInfo" + "diseaseSpreadStatistics", "http://schema.org/diseaseSpreadStatistics" + "dissolutionDate", "http://schema.org/dissolutionDate" + "distance", "http://schema.org/distance" + "distinguishingSign", "http://schema.org/distinguishingSign" + "distribution", "http://schema.org/distribution" + "diversityPolicy", "http://schema.org/diversityPolicy" + "diversityStaffingReport", "http://schema.org/diversityStaffingReport" + "documentation", "http://schema.org/documentation" + "doesNotShip", "http://schema.org/doesNotShip" + "domainIncludes", "http://schema.org/domainIncludes" + "domiciledMortgage", "http://schema.org/domiciledMortgage" + "doorTime", "http://schema.org/doorTime" + "dosageForm", "http://schema.org/dosageForm" + "doseSchedule", "http://schema.org/doseSchedule" + "doseUnit", "http://schema.org/doseUnit" + "doseValue", "http://schema.org/doseValue" + "downPayment", "http://schema.org/downPayment" + "downloadUrl", "http://schema.org/downloadUrl" + "downvoteCount", "http://schema.org/downvoteCount" + "drainsTo", "http://schema.org/drainsTo" + "driveWheelConfiguration", "http://schema.org/driveWheelConfiguration" + "dropoffLocation", "http://schema.org/dropoffLocation" + "dropoffTime", "http://schema.org/dropoffTime" + "drug", "http://schema.org/drug" + "drugClass", "http://schema.org/drugClass" + "drugUnit", "http://schema.org/drugUnit" + "duns", "http://schema.org/duns" + "duplicateTherapy", "http://schema.org/duplicateTherapy" + "duration", "http://schema.org/duration" + "durationOfWarranty", "http://schema.org/durationOfWarranty" + "duringMedia", "http://schema.org/duringMedia" + "earlyPrepaymentPenalty", "http://schema.org/earlyPrepaymentPenalty" + "editEIDR", "http://schema.org/editEIDR" + "editor", "http://schema.org/editor" + "eduQuestionType", "http://schema.org/eduQuestionType" + "educationRequirements", "http://schema.org/educationRequirements" + "educationalAlignment", "http://schema.org/educationalAlignment" + "educationalCredentialAwarded", "http://schema.org/educationalCredentialAwarded" + "educationalFramework", "http://schema.org/educationalFramework" + "educationalLevel", "http://schema.org/educationalLevel" + "educationalProgramMode", "http://schema.org/educationalProgramMode" + "educationalRole", "http://schema.org/educationalRole" + "educationalUse", "http://schema.org/educationalUse" + "elevation", "http://schema.org/elevation" + "eligibilityToWorkRequirement", "http://schema.org/eligibilityToWorkRequirement" + "eligibleCustomerType", "http://schema.org/eligibleCustomerType" + "eligibleDuration", "http://schema.org/eligibleDuration" + "eligibleQuantity", "http://schema.org/eligibleQuantity" + "eligibleRegion", "http://schema.org/eligibleRegion" + "eligibleTransactionVolume", "http://schema.org/eligibleTransactionVolume" + "email", "http://schema.org/email" + "embedUrl", "http://schema.org/embedUrl" + "emissionsCO2", "http://schema.org/emissionsCO2" + "employee", "http://schema.org/employee" + "employees", "http://schema.org/employees" + "employerOverview", "http://schema.org/employerOverview" + "employmentType", "http://schema.org/employmentType" + "employmentUnit", "http://schema.org/employmentUnit" + "encodesCreativeWork", "http://schema.org/encodesCreativeWork" + "encoding", "http://schema.org/encoding" + "encodingFormat", "http://schema.org/encodingFormat" + "encodingType", "http://schema.org/encodingType" + "encodings", "http://schema.org/encodings" + "endDate", "http://schema.org/endDate" + "endOffset", "http://schema.org/endOffset" + "endTime", "http://schema.org/endTime" + "endorsee", "http://schema.org/endorsee" + "endorsers", "http://schema.org/endorsers" + "energyEfficiencyScaleMax", "http://schema.org/energyEfficiencyScaleMax" + "energyEfficiencyScaleMin", "http://schema.org/energyEfficiencyScaleMin" + "engineDisplacement", "http://schema.org/engineDisplacement" + "enginePower", "http://schema.org/enginePower" + "engineType", "http://schema.org/engineType" + "entertainmentBusiness", "http://schema.org/entertainmentBusiness" + "epidemiology", "http://schema.org/epidemiology" + "episode", "http://schema.org/episode" + "episodeNumber", "http://schema.org/episodeNumber" + "episodes", "http://schema.org/episodes" + "equal", "http://schema.org/equal" + "error", "http://schema.org/error" + "estimatedCost", "http://schema.org/estimatedCost" + "estimatedFlightDuration", "http://schema.org/estimatedFlightDuration" + "estimatedSalary", "http://schema.org/estimatedSalary" + "estimatesRiskOf", "http://schema.org/estimatesRiskOf" + "ethicsPolicy", "http://schema.org/ethicsPolicy" + "event", "http://schema.org/event" + "eventAttendanceMode", "http://schema.org/eventAttendanceMode" + "eventSchedule", "http://schema.org/eventSchedule" + "eventStatus", "http://schema.org/eventStatus" + "events", "http://schema.org/events" + "evidenceLevel", "http://schema.org/evidenceLevel" + "evidenceOrigin", "http://schema.org/evidenceOrigin" + "exampleOfWork", "http://schema.org/exampleOfWork" + "exceptDate", "http://schema.org/exceptDate" + "exchangeRateSpread", "http://schema.org/exchangeRateSpread" + "executableLibraryName", "http://schema.org/executableLibraryName" + "exerciseCourse", "http://schema.org/exerciseCourse" + "exercisePlan", "http://schema.org/exercisePlan" + "exerciseRelatedDiet", "http://schema.org/exerciseRelatedDiet" + "exerciseType", "http://schema.org/exerciseType" + "exifData", "http://schema.org/exifData" + "expectedArrivalFrom", "http://schema.org/expectedArrivalFrom" + "expectedArrivalUntil", "http://schema.org/expectedArrivalUntil" + "expectedPrognosis", "http://schema.org/expectedPrognosis" + "expectsAcceptanceOf", "http://schema.org/expectsAcceptanceOf" + "experienceRequirements", "http://schema.org/experienceRequirements" + "expertConsiderations", "http://schema.org/expertConsiderations" + "expires", "http://schema.org/expires" + "familyName", "http://schema.org/familyName" + "fatContent", "http://schema.org/fatContent" + "faxNumber", "http://schema.org/faxNumber" + "featureList", "http://schema.org/featureList" + "feesAndCommissionsSpecification", "http://schema.org/feesAndCommissionsSpecification" + "fiberContent", "http://schema.org/fiberContent" + "fileFormat", "http://schema.org/fileFormat" + "fileSize", "http://schema.org/fileSize" + "financialAidEligible", "http://schema.org/financialAidEligible" + "firstAppearance", "http://schema.org/firstAppearance" + "firstPerformance", "http://schema.org/firstPerformance" + "flightDistance", "http://schema.org/flightDistance" + "flightNumber", "http://schema.org/flightNumber" + "floorLevel", "http://schema.org/floorLevel" + "floorLimit", "http://schema.org/floorLimit" + "floorSize", "http://schema.org/floorSize" + "followee", "http://schema.org/followee" + "follows", "http://schema.org/follows" + "followup", "http://schema.org/followup" + "foodEstablishment", "http://schema.org/foodEstablishment" + "foodEvent", "http://schema.org/foodEvent" + "foodWarning", "http://schema.org/foodWarning" + "founder", "http://schema.org/founder" + "founders", "http://schema.org/founders" + "foundingDate", "http://schema.org/foundingDate" + "foundingLocation", "http://schema.org/foundingLocation" + "free", "http://schema.org/free" + "freeShippingThreshold", "http://schema.org/freeShippingThreshold" + "frequency", "http://schema.org/frequency" + "fromLocation", "http://schema.org/fromLocation" + "fuelCapacity", "http://schema.org/fuelCapacity" + "fuelConsumption", "http://schema.org/fuelConsumption" + "fuelEfficiency", "http://schema.org/fuelEfficiency" + "fuelType", "http://schema.org/fuelType" + "functionalClass", "http://schema.org/functionalClass" + "fundedItem", "http://schema.org/fundedItem" + "funder", "http://schema.org/funder" + "game", "http://schema.org/game" + "gameItem", "http://schema.org/gameItem" + "gameLocation", "http://schema.org/gameLocation" + "gamePlatform", "http://schema.org/gamePlatform" + "gameServer", "http://schema.org/gameServer" + "gameTip", "http://schema.org/gameTip" + "gender", "http://schema.org/gender" + "genre", "http://schema.org/genre" + "geo", "http://schema.org/geo" + "geoContains", "http://schema.org/geoContains" + "geoCoveredBy", "http://schema.org/geoCoveredBy" + "geoCovers", "http://schema.org/geoCovers" + "geoCrosses", "http://schema.org/geoCrosses" + "geoDisjoint", "http://schema.org/geoDisjoint" + "geoEquals", "http://schema.org/geoEquals" + "geoIntersects", "http://schema.org/geoIntersects" + "geoMidpoint", "http://schema.org/geoMidpoint" + "geoOverlaps", "http://schema.org/geoOverlaps" + "geoRadius", "http://schema.org/geoRadius" + "geoTouches", "http://schema.org/geoTouches" + "geoWithin", "http://schema.org/geoWithin" + "geographicArea", "http://schema.org/geographicArea" + "gettingTestedInfo", "http://schema.org/gettingTestedInfo" + "givenName", "http://schema.org/givenName" + "globalLocationNumber", "http://schema.org/globalLocationNumber" + "governmentBenefitsInfo", "http://schema.org/governmentBenefitsInfo" + "gracePeriod", "http://schema.org/gracePeriod" + "grantee", "http://schema.org/grantee" + "greater", "http://schema.org/greater" + "greaterOrEqual", "http://schema.org/greaterOrEqual" + "gtin", "http://schema.org/gtin" + "gtin12", "http://schema.org/gtin12" + "gtin13", "http://schema.org/gtin13" + "gtin14", "http://schema.org/gtin14" + "gtin8", "http://schema.org/gtin8" + "guideline", "http://schema.org/guideline" + "guidelineDate", "http://schema.org/guidelineDate" + "guidelineSubject", "http://schema.org/guidelineSubject" + "handlingTime", "http://schema.org/handlingTime" + "hasBroadcastChannel", "http://schema.org/hasBroadcastChannel" + "hasCategoryCode", "http://schema.org/hasCategoryCode" + "hasCourse", "http://schema.org/hasCourse" + "hasCourseInstance", "http://schema.org/hasCourseInstance" + "hasCredential", "http://schema.org/hasCredential" + "hasDefinedTerm", "http://schema.org/hasDefinedTerm" + "hasDeliveryMethod", "http://schema.org/hasDeliveryMethod" + "hasDigitalDocumentPermission", "http://schema.org/hasDigitalDocumentPermission" + "hasDriveThroughService", "http://schema.org/hasDriveThroughService" + "hasEnergyConsumptionDetails", "http://schema.org/hasEnergyConsumptionDetails" + "hasEnergyEfficiencyCategory", "http://schema.org/hasEnergyEfficiencyCategory" + "hasHealthAspect", "http://schema.org/hasHealthAspect" + "hasMap", "http://schema.org/hasMap" + "hasMenu", "http://schema.org/hasMenu" + "hasMenuItem", "http://schema.org/hasMenuItem" + "hasMenuSection", "http://schema.org/hasMenuSection" + "hasMerchantReturnPolicy", "http://schema.org/hasMerchantReturnPolicy" + "hasOccupation", "http://schema.org/hasOccupation" + "hasOfferCatalog", "http://schema.org/hasOfferCatalog" + "hasPOS", "http://schema.org/hasPOS" + "hasPart", "http://schema.org/hasPart" + "hasProductReturnPolicy", "http://schema.org/hasProductReturnPolicy" + "hasVariant", "http://schema.org/hasVariant" + "headline", "http://schema.org/headline" + "healthCondition", "http://schema.org/healthCondition" + "healthPlanCoinsuranceOption", "http://schema.org/healthPlanCoinsuranceOption" + "healthPlanCoinsuranceRate", "http://schema.org/healthPlanCoinsuranceRate" + "healthPlanCopay", "http://schema.org/healthPlanCopay" + "healthPlanCopayOption", "http://schema.org/healthPlanCopayOption" + "healthPlanCostSharing", "http://schema.org/healthPlanCostSharing" + "healthPlanDrugOption", "http://schema.org/healthPlanDrugOption" + "healthPlanDrugTier", "http://schema.org/healthPlanDrugTier" + "healthPlanId", "http://schema.org/healthPlanId" + "healthPlanMarketingUrl", "http://schema.org/healthPlanMarketingUrl" + "healthPlanNetworkId", "http://schema.org/healthPlanNetworkId" + "healthPlanNetworkTier", "http://schema.org/healthPlanNetworkTier" + "healthPlanPharmacyCategory", "http://schema.org/healthPlanPharmacyCategory" + "healthcareReportingData", "http://schema.org/healthcareReportingData" + "height", "http://schema.org/height" + "highPrice", "http://schema.org/highPrice" + "hiringOrganization", "http://schema.org/hiringOrganization" + "holdingArchive", "http://schema.org/holdingArchive" + "homeLocation", "http://schema.org/homeLocation" + "homeTeam", "http://schema.org/homeTeam" + "honorificPrefix", "http://schema.org/honorificPrefix" + "honorificSuffix", "http://schema.org/honorificSuffix" + "hospitalAffiliation", "http://schema.org/hospitalAffiliation" + "hostingOrganization", "http://schema.org/hostingOrganization" + "hoursAvailable", "http://schema.org/hoursAvailable" + "howPerformed", "http://schema.org/howPerformed" + "httpMethod", "http://schema.org/httpMethod" + "iataCode", "http://schema.org/iataCode" + "icaoCode", "http://schema.org/icaoCode" + "identifier", "http://schema.org/identifier" + "identifyingExam", "http://schema.org/identifyingExam" + "identifyingTest", "http://schema.org/identifyingTest" + "illustrator", "http://schema.org/illustrator" + "image", "http://schema.org/image" + "imagingTechnique", "http://schema.org/imagingTechnique" + "inAlbum", "http://schema.org/inAlbum" + "inBroadcastLineup", "http://schema.org/inBroadcastLineup" + "inCodeSet", "http://schema.org/inCodeSet" + "inDefinedTermSet", "http://schema.org/inDefinedTermSet" + "inLanguage", "http://schema.org/inLanguage" + "inPlaylist", "http://schema.org/inPlaylist" + "inProductGroupWithID", "http://schema.org/inProductGroupWithID" + "inStoreReturnsOffered", "http://schema.org/inStoreReturnsOffered" + "inSupportOf", "http://schema.org/inSupportOf" + "incentiveCompensation", "http://schema.org/incentiveCompensation" + "incentives", "http://schema.org/incentives" + "includedComposition", "http://schema.org/includedComposition" + "includedDataCatalog", "http://schema.org/includedDataCatalog" + "includedInDataCatalog", "http://schema.org/includedInDataCatalog" + "includedInHealthInsurancePlan", "http://schema.org/includedInHealthInsurancePlan" + "includedRiskFactor", "http://schema.org/includedRiskFactor" + "includesAttraction", "http://schema.org/includesAttraction" + "includesHealthPlanFormulary", "http://schema.org/includesHealthPlanFormulary" + "includesHealthPlanNetwork", "http://schema.org/includesHealthPlanNetwork" + "includesObject", "http://schema.org/includesObject" + "increasesRiskOf", "http://schema.org/increasesRiskOf" + "industry", "http://schema.org/industry" + "ineligibleRegion", "http://schema.org/ineligibleRegion" + "infectiousAgent", "http://schema.org/infectiousAgent" + "infectiousAgentClass", "http://schema.org/infectiousAgentClass" + "ingredients", "http://schema.org/ingredients" + "inker", "http://schema.org/inker" + "insertion", "http://schema.org/insertion" + "installUrl", "http://schema.org/installUrl" + "instructor", "http://schema.org/instructor" + "instrument", "http://schema.org/instrument" + "intensity", "http://schema.org/intensity" + "interactingDrug", "http://schema.org/interactingDrug" + "interactionCount", "http://schema.org/interactionCount" + "interactionService", "http://schema.org/interactionService" + "interactionStatistic", "http://schema.org/interactionStatistic" + "interactionType", "http://schema.org/interactionType" + "interactivityType", "http://schema.org/interactivityType" + "interestRate", "http://schema.org/interestRate" + "inventoryLevel", "http://schema.org/inventoryLevel" + "inverseOf", "http://schema.org/inverseOf" + "isAcceptingNewPatients", "http://schema.org/isAcceptingNewPatients" + "isAccessibleForFree", "http://schema.org/isAccessibleForFree" + "isAccessoryOrSparePartFor", "http://schema.org/isAccessoryOrSparePartFor" + "isAvailableGenerically", "http://schema.org/isAvailableGenerically" + "isBasedOn", "http://schema.org/isBasedOn" + "isBasedOnUrl", "http://schema.org/isBasedOnUrl" + "isConsumableFor", "http://schema.org/isConsumableFor" + "isFamilyFriendly", "http://schema.org/isFamilyFriendly" + "isGift", "http://schema.org/isGift" + "isLiveBroadcast", "http://schema.org/isLiveBroadcast" + "isPartOf", "http://schema.org/isPartOf" + "isPlanForApartment", "http://schema.org/isPlanForApartment" + "isProprietary", "http://schema.org/isProprietary" + "isRelatedTo", "http://schema.org/isRelatedTo" + "isResizable", "http://schema.org/isResizable" + "isSimilarTo", "http://schema.org/isSimilarTo" + "isUnlabelledFallback", "http://schema.org/isUnlabelledFallback" + "isVariantOf", "http://schema.org/isVariantOf" + "isbn", "http://schema.org/isbn" + "isicV4", "http://schema.org/isicV4" + "isrcCode", "http://schema.org/isrcCode" + "issn", "http://schema.org/issn" + "issueNumber", "http://schema.org/issueNumber" + "issuedBy", "http://schema.org/issuedBy" + "issuedThrough", "http://schema.org/issuedThrough" + "iswcCode", "http://schema.org/iswcCode" + "item", "http://schema.org/item" + "itemCondition", "http://schema.org/itemCondition" + "itemListElement", "http://schema.org/itemListElement" + "itemListOrder", "http://schema.org/itemListOrder" + "itemLocation", "http://schema.org/itemLocation" + "itemOffered", "http://schema.org/itemOffered" + "itemReviewed", "http://schema.org/itemReviewed" + "itemShipped", "http://schema.org/itemShipped" + "itinerary", "http://schema.org/itinerary" + "jobBenefits", "http://schema.org/jobBenefits" + "jobImmediateStart", "http://schema.org/jobImmediateStart" + "jobLocation", "http://schema.org/jobLocation" + "jobLocationType", "http://schema.org/jobLocationType" + "jobStartDate", "http://schema.org/jobStartDate" + "jobTitle", "http://schema.org/jobTitle" + "jurisdiction", "http://schema.org/jurisdiction" + "keywords", "http://schema.org/keywords" + "knownVehicleDamages", "http://schema.org/knownVehicleDamages" + "knows", "http://schema.org/knows" + "knowsAbout", "http://schema.org/knowsAbout" + "knowsLanguage", "http://schema.org/knowsLanguage" + "labelDetails", "http://schema.org/labelDetails" + "landlord", "http://schema.org/landlord" + "language", "http://schema.org/language" + "lastReviewed", "http://schema.org/lastReviewed" + "latitude", "http://schema.org/latitude" + "layoutImage", "http://schema.org/layoutImage" + "learningResourceType", "http://schema.org/learningResourceType" + "leaseLength", "http://schema.org/leaseLength" + "legalName", "http://schema.org/legalName" + "legalStatus", "http://schema.org/legalStatus" + "legislationApplies", "http://schema.org/legislationApplies" + "legislationChanges", "http://schema.org/legislationChanges" + "legislationConsolidates", "http://schema.org/legislationConsolidates" + "legislationDate", "http://schema.org/legislationDate" + "legislationDateVersion", "http://schema.org/legislationDateVersion" + "legislationIdentifier", "http://schema.org/legislationIdentifier" + "legislationJurisdiction", "http://schema.org/legislationJurisdiction" + "legislationLegalForce", "http://schema.org/legislationLegalForce" + "legislationLegalValue", "http://schema.org/legislationLegalValue" + "legislationPassedBy", "http://schema.org/legislationPassedBy" + "legislationResponsible", "http://schema.org/legislationResponsible" + "legislationTransposes", "http://schema.org/legislationTransposes" + "legislationType", "http://schema.org/legislationType" + "leiCode", "http://schema.org/leiCode" + "lender", "http://schema.org/lender" + "lesser", "http://schema.org/lesser" + "lesserOrEqual", "http://schema.org/lesserOrEqual" + "letterer", "http://schema.org/letterer" + "license", "http://schema.org/license" + "line", "http://schema.org/line" + "linkRelationship", "http://schema.org/linkRelationship" + "liveBlogUpdate", "http://schema.org/liveBlogUpdate" + "loanMortgageMandateAmount", "http://schema.org/loanMortgageMandateAmount" + "loanPaymentAmount", "http://schema.org/loanPaymentAmount" + "loanPaymentFrequency", "http://schema.org/loanPaymentFrequency" + "loanRepaymentForm", "http://schema.org/loanRepaymentForm" + "loanTerm", "http://schema.org/loanTerm" + "loanType", "http://schema.org/loanType" + "location", "http://schema.org/location" + "locationCreated", "http://schema.org/locationCreated" + "lodgingUnitDescription", "http://schema.org/lodgingUnitDescription" + "lodgingUnitType", "http://schema.org/lodgingUnitType" + "logo", "http://schema.org/logo" + "longitude", "http://schema.org/longitude" + "loser", "http://schema.org/loser" + "lowPrice", "http://schema.org/lowPrice" + "lyricist", "http://schema.org/lyricist" + "lyrics", "http://schema.org/lyrics" + "mainContentOfPage", "http://schema.org/mainContentOfPage" + "mainEntity", "http://schema.org/mainEntity" + "mainEntityOfPage", "http://schema.org/mainEntityOfPage" + "maintainer", "http://schema.org/maintainer" + "makesOffer", "http://schema.org/makesOffer" + "manufacturer", "http://schema.org/manufacturer" + "map", "http://schema.org/map" + "mapType", "http://schema.org/mapType" + "maps", "http://schema.org/maps" + "marginOfError", "http://schema.org/marginOfError" + "masthead", "http://schema.org/masthead" + "material", "http://schema.org/material" + "materialExtent", "http://schema.org/materialExtent" + "maxPrice", "http://schema.org/maxPrice" + "maxValue", "http://schema.org/maxValue" + "maximumAttendeeCapacity", "http://schema.org/maximumAttendeeCapacity" + "maximumEnrollment", "http://schema.org/maximumEnrollment" + "maximumIntake", "http://schema.org/maximumIntake" + "maximumPhysicalAttendeeCapacity", "http://schema.org/maximumPhysicalAttendeeCapacity" + "maximumVirtualAttendeeCapacity", "http://schema.org/maximumVirtualAttendeeCapacity" + "mealService", "http://schema.org/mealService" + "measuredProperty", "http://schema.org/measuredProperty" + "measuredValue", "http://schema.org/measuredValue" + "measurementTechnique", "http://schema.org/measurementTechnique" + "mechanismOfAction", "http://schema.org/mechanismOfAction" + "mediaAuthenticityCategory", "http://schema.org/mediaAuthenticityCategory" + "median", "http://schema.org/median" + "medicalAudience", "http://schema.org/medicalAudience" + "medicalSpecialty", "http://schema.org/medicalSpecialty" + "medicineSystem", "http://schema.org/medicineSystem" + "meetsEmissionStandard", "http://schema.org/meetsEmissionStandard" + "member", "http://schema.org/member" + "memberOf", "http://schema.org/memberOf" + "members", "http://schema.org/members" + "membershipNumber", "http://schema.org/membershipNumber" + "membershipPointsEarned", "http://schema.org/membershipPointsEarned" + "memoryRequirements", "http://schema.org/memoryRequirements" + "mentions", "http://schema.org/mentions" + "menu", "http://schema.org/menu" + "menuAddOn", "http://schema.org/menuAddOn" + "merchant", "http://schema.org/merchant" + "merchantReturnDays", "http://schema.org/merchantReturnDays" + "merchantReturnLink", "http://schema.org/merchantReturnLink" + "messageAttachment", "http://schema.org/messageAttachment" + "mileageFromOdometer", "http://schema.org/mileageFromOdometer" + "minPrice", "http://schema.org/minPrice" + "minValue", "http://schema.org/minValue" + "minimumPaymentDue", "http://schema.org/minimumPaymentDue" + "missionCoveragePrioritiesPolicy", "http://schema.org/missionCoveragePrioritiesPolicy" + "model", "http://schema.org/model" + "modelDate", "http://schema.org/modelDate" + "modifiedTime", "http://schema.org/modifiedTime" + "monthlyMinimumRepaymentAmount", "http://schema.org/monthlyMinimumRepaymentAmount" + "mpn", "http://schema.org/mpn" + "multipleValues", "http://schema.org/multipleValues" + "muscleAction", "http://schema.org/muscleAction" + "musicArrangement", "http://schema.org/musicArrangement" + "musicBy", "http://schema.org/musicBy" + "musicCompositionForm", "http://schema.org/musicCompositionForm" + "musicGroupMember", "http://schema.org/musicGroupMember" + "musicReleaseFormat", "http://schema.org/musicReleaseFormat" + "musicalKey", "http://schema.org/musicalKey" + "naics", "http://schema.org/naics" + "name", "http://schema.org/name" + "namedPosition", "http://schema.org/namedPosition" + "nationality", "http://schema.org/nationality" + "naturalProgression", "http://schema.org/naturalProgression" + "nerve", "http://schema.org/nerve" + "nerveMotor", "http://schema.org/nerveMotor" + "netWorth", "http://schema.org/netWorth" + "newsUpdatesAndGuidelines", "http://schema.org/newsUpdatesAndGuidelines" + "nextItem", "http://schema.org/nextItem" + "noBylinesPolicy", "http://schema.org/noBylinesPolicy" + "nonEqual", "http://schema.org/nonEqual" + "nonProprietaryName", "http://schema.org/nonProprietaryName" + "nonprofitStatus", "http://schema.org/nonprofitStatus" + "normalRange", "http://schema.org/normalRange" + "nsn", "http://schema.org/nsn" + "numAdults", "http://schema.org/numAdults" + "numChildren", "http://schema.org/numChildren" + "numConstraints", "http://schema.org/numConstraints" + "numTracks", "http://schema.org/numTracks" + "numberOfAccommodationUnits", "http://schema.org/numberOfAccommodationUnits" + "numberOfAirbags", "http://schema.org/numberOfAirbags" + "numberOfAvailableAccommodationUnits", "http://schema.org/numberOfAvailableAccommodationUnits" + "numberOfAxles", "http://schema.org/numberOfAxles" + "numberOfBathroomsTotal", "http://schema.org/numberOfBathroomsTotal" + "numberOfBedrooms", "http://schema.org/numberOfBedrooms" + "numberOfBeds", "http://schema.org/numberOfBeds" + "numberOfCredits", "http://schema.org/numberOfCredits" + "numberOfDoors", "http://schema.org/numberOfDoors" + "numberOfEmployees", "http://schema.org/numberOfEmployees" + "numberOfEpisodes", "http://schema.org/numberOfEpisodes" + "numberOfForwardGears", "http://schema.org/numberOfForwardGears" + "numberOfFullBathrooms", "http://schema.org/numberOfFullBathrooms" + "numberOfItems", "http://schema.org/numberOfItems" + "numberOfLoanPayments", "http://schema.org/numberOfLoanPayments" + "numberOfPages", "http://schema.org/numberOfPages" + "numberOfPartialBathrooms", "http://schema.org/numberOfPartialBathrooms" + "numberOfPlayers", "http://schema.org/numberOfPlayers" + "numberOfPreviousOwners", "http://schema.org/numberOfPreviousOwners" + "numberOfRooms", "http://schema.org/numberOfRooms" + "numberOfSeasons", "http://schema.org/numberOfSeasons" + "numberedPosition", "http://schema.org/numberedPosition" + "nutrition", "http://schema.org/nutrition" + "object", "http://schema.org/object" + "observationDate", "http://schema.org/observationDate" + "observedNode", "http://schema.org/observedNode" + "occupancy", "http://schema.org/occupancy" + "occupationLocation", "http://schema.org/occupationLocation" + "occupationalCategory", "http://schema.org/occupationalCategory" + "occupationalCredentialAwarded", "http://schema.org/occupationalCredentialAwarded" + "offerCount", "http://schema.org/offerCount" + "offeredBy", "http://schema.org/offeredBy" + "offers", "http://schema.org/offers" + "offersPrescriptionByMail", "http://schema.org/offersPrescriptionByMail" + "openingHours", "http://schema.org/openingHours" + "openingHoursSpecification", "http://schema.org/openingHoursSpecification" + "opens", "http://schema.org/opens" + "operatingSystem", "http://schema.org/operatingSystem" + "opponent", "http://schema.org/opponent" + "option", "http://schema.org/option" + "orderDate", "http://schema.org/orderDate" + "orderDelivery", "http://schema.org/orderDelivery" + "orderItemNumber", "http://schema.org/orderItemNumber" + "orderItemStatus", "http://schema.org/orderItemStatus" + "orderNumber", "http://schema.org/orderNumber" + "orderQuantity", "http://schema.org/orderQuantity" + "orderStatus", "http://schema.org/orderStatus" + "orderedItem", "http://schema.org/orderedItem" + "organizer", "http://schema.org/organizer" + "originAddress", "http://schema.org/originAddress" + "originatesFrom", "http://schema.org/originatesFrom" + "overdosage", "http://schema.org/overdosage" + "ownedFrom", "http://schema.org/ownedFrom" + "ownedThrough", "http://schema.org/ownedThrough" + "ownershipFundingInfo", "http://schema.org/ownershipFundingInfo" + "owns", "http://schema.org/owns" + "pageEnd", "http://schema.org/pageEnd" + "pageStart", "http://schema.org/pageStart" + "pagination", "http://schema.org/pagination" + "parent", "http://schema.org/parent" + "parentItem", "http://schema.org/parentItem" + "parentOrganization", "http://schema.org/parentOrganization" + "parentService", "http://schema.org/parentService" + "parents", "http://schema.org/parents" + "partOfEpisode", "http://schema.org/partOfEpisode" + "partOfInvoice", "http://schema.org/partOfInvoice" + "partOfOrder", "http://schema.org/partOfOrder" + "partOfSeason", "http://schema.org/partOfSeason" + "partOfSeries", "http://schema.org/partOfSeries" + "partOfSystem", "http://schema.org/partOfSystem" + "partOfTVSeries", "http://schema.org/partOfTVSeries" + "partOfTrip", "http://schema.org/partOfTrip" + "participant", "http://schema.org/participant" + "partySize", "http://schema.org/partySize" + "passengerPriorityStatus", "http://schema.org/passengerPriorityStatus" + "passengerSequenceNumber", "http://schema.org/passengerSequenceNumber" + "pathophysiology", "http://schema.org/pathophysiology" + "pattern", "http://schema.org/pattern" + "payload", "http://schema.org/payload" + "paymentAccepted", "http://schema.org/paymentAccepted" + "paymentDue", "http://schema.org/paymentDue" + "paymentDueDate", "http://schema.org/paymentDueDate" + "paymentMethod", "http://schema.org/paymentMethod" + "paymentMethodId", "http://schema.org/paymentMethodId" + "paymentStatus", "http://schema.org/paymentStatus" + "paymentUrl", "http://schema.org/paymentUrl" + "penciler", "http://schema.org/penciler" + "percentile10", "http://schema.org/percentile10" + "percentile25", "http://schema.org/percentile25" + "percentile75", "http://schema.org/percentile75" + "percentile90", "http://schema.org/percentile90" + "performTime", "http://schema.org/performTime" + "performer", "http://schema.org/performer" + "performerIn", "http://schema.org/performerIn" + "performers", "http://schema.org/performers" + "permissionType", "http://schema.org/permissionType" + "permissions", "http://schema.org/permissions" + "permitAudience", "http://schema.org/permitAudience" + "permittedUsage", "http://schema.org/permittedUsage" + "petsAllowed", "http://schema.org/petsAllowed" + "phoneticText", "http://schema.org/phoneticText" + "photo", "http://schema.org/photo" + "photos", "http://schema.org/photos" + "physicalRequirement", "http://schema.org/physicalRequirement" + "physiologicalBenefits", "http://schema.org/physiologicalBenefits" + "pickupLocation", "http://schema.org/pickupLocation" + "pickupTime", "http://schema.org/pickupTime" + "playMode", "http://schema.org/playMode" + "playerType", "http://schema.org/playerType" + "playersOnline", "http://schema.org/playersOnline" + "polygon", "http://schema.org/polygon" + "populationType", "http://schema.org/populationType" + "position", "http://schema.org/position" + "possibleComplication", "http://schema.org/possibleComplication" + "possibleTreatment", "http://schema.org/possibleTreatment" + "postOfficeBoxNumber", "http://schema.org/postOfficeBoxNumber" + "postOp", "http://schema.org/postOp" + "postalCode", "http://schema.org/postalCode" + "postalCodeBegin", "http://schema.org/postalCodeBegin" + "postalCodeEnd", "http://schema.org/postalCodeEnd" + "postalCodePrefix", "http://schema.org/postalCodePrefix" + "postalCodeRange", "http://schema.org/postalCodeRange" + "potentialAction", "http://schema.org/potentialAction" + "preOp", "http://schema.org/preOp" + "predecessorOf", "http://schema.org/predecessorOf" + "pregnancyCategory", "http://schema.org/pregnancyCategory" + "pregnancyWarning", "http://schema.org/pregnancyWarning" + "prepTime", "http://schema.org/prepTime" + "preparation", "http://schema.org/preparation" + "prescribingInfo", "http://schema.org/prescribingInfo" + "prescriptionStatus", "http://schema.org/prescriptionStatus" + "previousItem", "http://schema.org/previousItem" + "previousStartDate", "http://schema.org/previousStartDate" + "price", "http://schema.org/price" + "priceComponent", "http://schema.org/priceComponent" + "priceCurrency", "http://schema.org/priceCurrency" + "priceRange", "http://schema.org/priceRange" + "priceSpecification", "http://schema.org/priceSpecification" + "priceType", "http://schema.org/priceType" + "priceValidUntil", "http://schema.org/priceValidUntil" + "primaryImageOfPage", "http://schema.org/primaryImageOfPage" + "primaryPrevention", "http://schema.org/primaryPrevention" + "printColumn", "http://schema.org/printColumn" + "printEdition", "http://schema.org/printEdition" + "printPage", "http://schema.org/printPage" + "printSection", "http://schema.org/printSection" + "procedure", "http://schema.org/procedure" + "procedureType", "http://schema.org/procedureType" + "processingTime", "http://schema.org/processingTime" + "processorRequirements", "http://schema.org/processorRequirements" + "producer", "http://schema.org/producer" + "produces", "http://schema.org/produces" + "productGroupID", "http://schema.org/productGroupID" + "productID", "http://schema.org/productID" + "productReturnDays", "http://schema.org/productReturnDays" + "productReturnLink", "http://schema.org/productReturnLink" + "productSupported", "http://schema.org/productSupported" + "productionCompany", "http://schema.org/productionCompany" + "productionDate", "http://schema.org/productionDate" + "proficiencyLevel", "http://schema.org/proficiencyLevel" + "programMembershipUsed", "http://schema.org/programMembershipUsed" + "programName", "http://schema.org/programName" + "programPrerequisites", "http://schema.org/programPrerequisites" + "programType", "http://schema.org/programType" + "programmingLanguage", "http://schema.org/programmingLanguage" + "programmingModel", "http://schema.org/programmingModel" + "propertyID", "http://schema.org/propertyID" + "proprietaryName", "http://schema.org/proprietaryName" + "proteinContent", "http://schema.org/proteinContent" + "provider", "http://schema.org/provider" + "providerMobility", "http://schema.org/providerMobility" + "providesBroadcastService", "http://schema.org/providesBroadcastService" + "providesService", "http://schema.org/providesService" + "publicAccess", "http://schema.org/publicAccess" + "publicTransportClosuresInfo", "http://schema.org/publicTransportClosuresInfo" + "publication", "http://schema.org/publication" + "publicationType", "http://schema.org/publicationType" + "publishedBy", "http://schema.org/publishedBy" + "publishedOn", "http://schema.org/publishedOn" + "publisher", "http://schema.org/publisher" + "publisherImprint", "http://schema.org/publisherImprint" + "publishingPrinciples", "http://schema.org/publishingPrinciples" + "purchaseDate", "http://schema.org/purchaseDate" + "qualifications", "http://schema.org/qualifications" + "quarantineGuidelines", "http://schema.org/quarantineGuidelines" + "query", "http://schema.org/query" + "quest", "http://schema.org/quest" + "question", "http://schema.org/question" + "rangeIncludes", "http://schema.org/rangeIncludes" + "ratingCount", "http://schema.org/ratingCount" + "ratingExplanation", "http://schema.org/ratingExplanation" + "ratingValue", "http://schema.org/ratingValue" + "readBy", "http://schema.org/readBy" + "readonlyValue", "http://schema.org/readonlyValue" + "realEstateAgent", "http://schema.org/realEstateAgent" + "recipe", "http://schema.org/recipe" + "recipeCategory", "http://schema.org/recipeCategory" + "recipeCuisine", "http://schema.org/recipeCuisine" + "recipeIngredient", "http://schema.org/recipeIngredient" + "recipeInstructions", "http://schema.org/recipeInstructions" + "recipeYield", "http://schema.org/recipeYield" + "recipient", "http://schema.org/recipient" + "recognizedBy", "http://schema.org/recognizedBy" + "recognizingAuthority", "http://schema.org/recognizingAuthority" + "recommendationStrength", "http://schema.org/recommendationStrength" + "recommendedIntake", "http://schema.org/recommendedIntake" + "recordLabel", "http://schema.org/recordLabel" + "recordedAs", "http://schema.org/recordedAs" + "recordedAt", "http://schema.org/recordedAt" + "recordedIn", "http://schema.org/recordedIn" + "recordingOf", "http://schema.org/recordingOf" + "recourseLoan", "http://schema.org/recourseLoan" + "referenceQuantity", "http://schema.org/referenceQuantity" + "referencesOrder", "http://schema.org/referencesOrder" + "refundType", "http://schema.org/refundType" + "regionDrained", "http://schema.org/regionDrained" + "regionsAllowed", "http://schema.org/regionsAllowed" + "relatedAnatomy", "http://schema.org/relatedAnatomy" + "relatedCondition", "http://schema.org/relatedCondition" + "relatedDrug", "http://schema.org/relatedDrug" + "relatedLink", "http://schema.org/relatedLink" + "relatedStructure", "http://schema.org/relatedStructure" + "relatedTherapy", "http://schema.org/relatedTherapy" + "relatedTo", "http://schema.org/relatedTo" + "releaseDate", "http://schema.org/releaseDate" + "releaseNotes", "http://schema.org/releaseNotes" + "releaseOf", "http://schema.org/releaseOf" + "releasedEvent", "http://schema.org/releasedEvent" + "relevantOccupation", "http://schema.org/relevantOccupation" + "relevantSpecialty", "http://schema.org/relevantSpecialty" + "remainingAttendeeCapacity", "http://schema.org/remainingAttendeeCapacity" + "renegotiableLoan", "http://schema.org/renegotiableLoan" + "repeatCount", "http://schema.org/repeatCount" + "repeatFrequency", "http://schema.org/repeatFrequency" + "repetitions", "http://schema.org/repetitions" + "replacee", "http://schema.org/replacee" + "replacer", "http://schema.org/replacer" + "replyToUrl", "http://schema.org/replyToUrl" + "reportNumber", "http://schema.org/reportNumber" + "representativeOfPage", "http://schema.org/representativeOfPage" + "requiredCollateral", "http://schema.org/requiredCollateral" + "requiredGender", "http://schema.org/requiredGender" + "requiredMaxAge", "http://schema.org/requiredMaxAge" + "requiredMinAge", "http://schema.org/requiredMinAge" + "requiredQuantity", "http://schema.org/requiredQuantity" + "requirements", "http://schema.org/requirements" + "requiresSubscription", "http://schema.org/requiresSubscription" + "reservationFor", "http://schema.org/reservationFor" + "reservationId", "http://schema.org/reservationId" + "reservationStatus", "http://schema.org/reservationStatus" + "reservedTicket", "http://schema.org/reservedTicket" + "responsibilities", "http://schema.org/responsibilities" + "restPeriods", "http://schema.org/restPeriods" + "result", "http://schema.org/result" + "resultComment", "http://schema.org/resultComment" + "resultReview", "http://schema.org/resultReview" + "returnFees", "http://schema.org/returnFees" + "returnPolicyCategory", "http://schema.org/returnPolicyCategory" + "review", "http://schema.org/review" + "reviewAspect", "http://schema.org/reviewAspect" + "reviewBody", "http://schema.org/reviewBody" + "reviewCount", "http://schema.org/reviewCount" + "reviewRating", "http://schema.org/reviewRating" + "reviewedBy", "http://schema.org/reviewedBy" + "reviews", "http://schema.org/reviews" + "riskFactor", "http://schema.org/riskFactor" + "risks", "http://schema.org/risks" + "roleName", "http://schema.org/roleName" + "roofLoad", "http://schema.org/roofLoad" + "rsvpResponse", "http://schema.org/rsvpResponse" + "runsTo", "http://schema.org/runsTo" + "runtime", "http://schema.org/runtime" + "runtimePlatform", "http://schema.org/runtimePlatform" + "rxcui", "http://schema.org/rxcui" + "safetyConsideration", "http://schema.org/safetyConsideration" + "salaryCurrency", "http://schema.org/salaryCurrency" + "salaryUponCompletion", "http://schema.org/salaryUponCompletion" + "sameAs", "http://schema.org/sameAs" + "sampleType", "http://schema.org/sampleType" + "saturatedFatContent", "http://schema.org/saturatedFatContent" + "scheduleTimezone", "http://schema.org/scheduleTimezone" + "scheduledPaymentDate", "http://schema.org/scheduledPaymentDate" + "scheduledTime", "http://schema.org/scheduledTime" + "schemaVersion", "http://schema.org/schemaVersion" + "schoolClosuresInfo", "http://schema.org/schoolClosuresInfo" + "screenCount", "http://schema.org/screenCount" + "screenshot", "http://schema.org/screenshot" + "sdDatePublished", "http://schema.org/sdDatePublished" + "sdLicense", "http://schema.org/sdLicense" + "sdPublisher", "http://schema.org/sdPublisher" + "season", "http://schema.org/season" + "seasonNumber", "http://schema.org/seasonNumber" + "seasons", "http://schema.org/seasons" + "seatNumber", "http://schema.org/seatNumber" + "seatRow", "http://schema.org/seatRow" + "seatSection", "http://schema.org/seatSection" + "seatingCapacity", "http://schema.org/seatingCapacity" + "seatingType", "http://schema.org/seatingType" + "secondaryPrevention", "http://schema.org/secondaryPrevention" + "securityClearanceRequirement", "http://schema.org/securityClearanceRequirement" + "securityScreening", "http://schema.org/securityScreening" + "seeks", "http://schema.org/seeks" + "seller", "http://schema.org/seller" + "sender", "http://schema.org/sender" + "sensoryRequirement", "http://schema.org/sensoryRequirement" + "sensoryUnit", "http://schema.org/sensoryUnit" + "serialNumber", "http://schema.org/serialNumber" + "seriousAdverseOutcome", "http://schema.org/seriousAdverseOutcome" + "serverStatus", "http://schema.org/serverStatus" + "servesCuisine", "http://schema.org/servesCuisine" + "serviceArea", "http://schema.org/serviceArea" + "serviceAudience", "http://schema.org/serviceAudience" + "serviceLocation", "http://schema.org/serviceLocation" + "serviceOperator", "http://schema.org/serviceOperator" + "serviceOutput", "http://schema.org/serviceOutput" + "servicePhone", "http://schema.org/servicePhone" + "servicePostalAddress", "http://schema.org/servicePostalAddress" + "serviceSmsNumber", "http://schema.org/serviceSmsNumber" + "serviceType", "http://schema.org/serviceType" + "serviceUrl", "http://schema.org/serviceUrl" + "servingSize", "http://schema.org/servingSize" + "sharedContent", "http://schema.org/sharedContent" + "shippingDestination", "http://schema.org/shippingDestination" + "shippingDetails", "http://schema.org/shippingDetails" + "shippingLabel", "http://schema.org/shippingLabel" + "shippingRate", "http://schema.org/shippingRate" + "shippingSettingsLink", "http://schema.org/shippingSettingsLink" + "sibling", "http://schema.org/sibling" + "siblings", "http://schema.org/siblings" + "signDetected", "http://schema.org/signDetected" + "signOrSymptom", "http://schema.org/signOrSymptom" + "significance", "http://schema.org/significance" + "significantLink", "http://schema.org/significantLink" + "significantLinks", "http://schema.org/significantLinks" + "size", "http://schema.org/size" + "skills", "http://schema.org/skills" + "sku", "http://schema.org/sku" + "slogan", "http://schema.org/slogan" + "smokingAllowed", "http://schema.org/smokingAllowed" + "sodiumContent", "http://schema.org/sodiumContent" + "softwareAddOn", "http://schema.org/softwareAddOn" + "softwareHelp", "http://schema.org/softwareHelp" + "softwareRequirements", "http://schema.org/softwareRequirements" + "softwareVersion", "http://schema.org/softwareVersion" + "sourceOrganization", "http://schema.org/sourceOrganization" + "sourcedFrom", "http://schema.org/sourcedFrom" + "spatial", "http://schema.org/spatial" + "spatialCoverage", "http://schema.org/spatialCoverage" + "speakable", "http://schema.org/speakable" + "specialCommitments", "http://schema.org/specialCommitments" + "specialOpeningHoursSpecification", "http://schema.org/specialOpeningHoursSpecification" + "specialty", "http://schema.org/specialty" + "speechToTextMarkup", "http://schema.org/speechToTextMarkup" + "speed", "http://schema.org/speed" + "spokenByCharacter", "http://schema.org/spokenByCharacter" + "sponsor", "http://schema.org/sponsor" + "sport", "http://schema.org/sport" + "sportsActivityLocation", "http://schema.org/sportsActivityLocation" + "sportsEvent", "http://schema.org/sportsEvent" + "sportsTeam", "http://schema.org/sportsTeam" + "spouse", "http://schema.org/spouse" + "stage", "http://schema.org/stage" + "stageAsNumber", "http://schema.org/stageAsNumber" + "starRating", "http://schema.org/starRating" + "startDate", "http://schema.org/startDate" + "startOffset", "http://schema.org/startOffset" + "startTime", "http://schema.org/startTime" + "status", "http://schema.org/status" + "steeringPosition", "http://schema.org/steeringPosition" + "step", "http://schema.org/step" + "stepValue", "http://schema.org/stepValue" + "steps", "http://schema.org/steps" + "storageRequirements", "http://schema.org/storageRequirements" + "streetAddress", "http://schema.org/streetAddress" + "strengthUnit", "http://schema.org/strengthUnit" + "strengthValue", "http://schema.org/strengthValue" + "structuralClass", "http://schema.org/structuralClass" + "study", "http://schema.org/study" + "studyDesign", "http://schema.org/studyDesign" + "studyLocation", "http://schema.org/studyLocation" + "studySubject", "http://schema.org/studySubject" + "stupidProperty", "http://schema.org/stupidProperty" + "subEvent", "http://schema.org/subEvent" + "subEvents", "http://schema.org/subEvents" + "subOrganization", "http://schema.org/subOrganization" + "subReservation", "http://schema.org/subReservation" + "subStageSuffix", "http://schema.org/subStageSuffix" + "subStructure", "http://schema.org/subStructure" + "subTest", "http://schema.org/subTest" + "subTrip", "http://schema.org/subTrip" + "subjectOf", "http://schema.org/subjectOf" + "subtitleLanguage", "http://schema.org/subtitleLanguage" + "successorOf", "http://schema.org/successorOf" + "sugarContent", "http://schema.org/sugarContent" + "suggestedAnswer", "http://schema.org/suggestedAnswer" + "suggestedGender", "http://schema.org/suggestedGender" + "suggestedMaxAge", "http://schema.org/suggestedMaxAge" + "suggestedMinAge", "http://schema.org/suggestedMinAge" + "suitableForDiet", "http://schema.org/suitableForDiet" + "superEvent", "http://schema.org/superEvent" + "supersededBy", "http://schema.org/supersededBy" + "supply", "http://schema.org/supply" + "supplyTo", "http://schema.org/supplyTo" + "supportingData", "http://schema.org/supportingData" + "surface", "http://schema.org/surface" + "target", "http://schema.org/target" + "targetCollection", "http://schema.org/targetCollection" + "targetDescription", "http://schema.org/targetDescription" + "targetName", "http://schema.org/targetName" + "targetPlatform", "http://schema.org/targetPlatform" + "targetPopulation", "http://schema.org/targetPopulation" + "targetProduct", "http://schema.org/targetProduct" + "targetUrl", "http://schema.org/targetUrl" + "taxID", "http://schema.org/taxID" + "teaches", "http://schema.org/teaches" + "telephone", "http://schema.org/telephone" + "temporal", "http://schema.org/temporal" + "temporalCoverage", "http://schema.org/temporalCoverage" + "termCode", "http://schema.org/termCode" + "termDuration", "http://schema.org/termDuration" + "termsOfService", "http://schema.org/termsOfService" + "termsPerYear", "http://schema.org/termsPerYear" + "text", "http://schema.org/text" + "textValue", "http://schema.org/textValue" + "thumbnail", "http://schema.org/thumbnail" + "thumbnailUrl", "http://schema.org/thumbnailUrl" + "tickerSymbol", "http://schema.org/tickerSymbol" + "ticketNumber", "http://schema.org/ticketNumber" + "ticketToken", "http://schema.org/ticketToken" + "ticketedSeat", "http://schema.org/ticketedSeat" + "timeOfDay", "http://schema.org/timeOfDay" + "timeRequired", "http://schema.org/timeRequired" + "timeToComplete", "http://schema.org/timeToComplete" + "tissueSample", "http://schema.org/tissueSample" + "title", "http://schema.org/title" + "titleEIDR", "http://schema.org/titleEIDR" + "toLocation", "http://schema.org/toLocation" + "toRecipient", "http://schema.org/toRecipient" + "tongueWeight", "http://schema.org/tongueWeight" + "tool", "http://schema.org/tool" + "torque", "http://schema.org/torque" + "totalJobOpenings", "http://schema.org/totalJobOpenings" + "totalPaymentDue", "http://schema.org/totalPaymentDue" + "totalPrice", "http://schema.org/totalPrice" + "totalTime", "http://schema.org/totalTime" + "tourBookingPage", "http://schema.org/tourBookingPage" + "touristType", "http://schema.org/touristType" + "track", "http://schema.org/track" + "trackingNumber", "http://schema.org/trackingNumber" + "trackingUrl", "http://schema.org/trackingUrl" + "tracks", "http://schema.org/tracks" + "trailer", "http://schema.org/trailer" + "trailerWeight", "http://schema.org/trailerWeight" + "trainName", "http://schema.org/trainName" + "trainNumber", "http://schema.org/trainNumber" + "trainingSalary", "http://schema.org/trainingSalary" + "transFatContent", "http://schema.org/transFatContent" + "transcript", "http://schema.org/transcript" + "transitTime", "http://schema.org/transitTime" + "transitTimeLabel", "http://schema.org/transitTimeLabel" + "translationOfWork", "http://schema.org/translationOfWork" + "translator", "http://schema.org/translator" + "transmissionMethod", "http://schema.org/transmissionMethod" + "travelBans", "http://schema.org/travelBans" + "trialDesign", "http://schema.org/trialDesign" + "tributary", "http://schema.org/tributary" + "typeOfBed", "http://schema.org/typeOfBed" + "typeOfGood", "http://schema.org/typeOfGood" + "typicalAgeRange", "http://schema.org/typicalAgeRange" + "typicalCreditsPerTerm", "http://schema.org/typicalCreditsPerTerm" + "typicalTest", "http://schema.org/typicalTest" + "underName", "http://schema.org/underName" + "unitCode", "http://schema.org/unitCode" + "unitText", "http://schema.org/unitText" + "unnamedSourcesPolicy", "http://schema.org/unnamedSourcesPolicy" + "unsaturatedFatContent", "http://schema.org/unsaturatedFatContent" + "uploadDate", "http://schema.org/uploadDate" + "upvoteCount", "http://schema.org/upvoteCount" + "url", "http://schema.org/url" + "urlTemplate", "http://schema.org/urlTemplate" + "usageInfo", "http://schema.org/usageInfo" + "usedToDiagnose", "http://schema.org/usedToDiagnose" + "userInteractionCount", "http://schema.org/userInteractionCount" + "usesDevice", "http://schema.org/usesDevice" + "usesHealthPlanIdStandard", "http://schema.org/usesHealthPlanIdStandard" + "validFor", "http://schema.org/validFor" + "validFrom", "http://schema.org/validFrom" + "validIn", "http://schema.org/validIn" + "validThrough", "http://schema.org/validThrough" + "validUntil", "http://schema.org/validUntil" + "value", "http://schema.org/value" + "valueAddedTaxIncluded", "http://schema.org/valueAddedTaxIncluded" + "valueMaxLength", "http://schema.org/valueMaxLength" + "valueMinLength", "http://schema.org/valueMinLength" + "valueName", "http://schema.org/valueName" + "valuePattern", "http://schema.org/valuePattern" + "valueReference", "http://schema.org/valueReference" + "valueRequired", "http://schema.org/valueRequired" + "variableMeasured", "http://schema.org/variableMeasured" + "variablesMeasured", "http://schema.org/variablesMeasured" + "variantCover", "http://schema.org/variantCover" + "variesBy", "http://schema.org/variesBy" + "vatID", "http://schema.org/vatID" + "vehicleConfiguration", "http://schema.org/vehicleConfiguration" + "vehicleEngine", "http://schema.org/vehicleEngine" + "vehicleIdentificationNumber", "http://schema.org/vehicleIdentificationNumber" + "vehicleInteriorColor", "http://schema.org/vehicleInteriorColor" + "vehicleInteriorType", "http://schema.org/vehicleInteriorType" + "vehicleModelDate", "http://schema.org/vehicleModelDate" + "vehicleSeatingCapacity", "http://schema.org/vehicleSeatingCapacity" + "vehicleSpecialUsage", "http://schema.org/vehicleSpecialUsage" + "vehicleTransmission", "http://schema.org/vehicleTransmission" + "vendor", "http://schema.org/vendor" + "verificationFactCheckingPolicy", "http://schema.org/verificationFactCheckingPolicy" + "version", "http://schema.org/version" + "video", "http://schema.org/video" + "videoFormat", "http://schema.org/videoFormat" + "videoFrameSize", "http://schema.org/videoFrameSize" + "videoQuality", "http://schema.org/videoQuality" + "volumeNumber", "http://schema.org/volumeNumber" + "warning", "http://schema.org/warning" + "warranty", "http://schema.org/warranty" + "warrantyPromise", "http://schema.org/warrantyPromise" + "warrantyScope", "http://schema.org/warrantyScope" + "webCheckinTime", "http://schema.org/webCheckinTime" + "webFeed", "http://schema.org/webFeed" + "weight", "http://schema.org/weight" + "weightTotal", "http://schema.org/weightTotal" + "wheelbase", "http://schema.org/wheelbase" + "width", "http://schema.org/width" + "winner", "http://schema.org/winner" + "wordCount", "http://schema.org/wordCount" + "workExample", "http://schema.org/workExample" + "workFeatured", "http://schema.org/workFeatured" + "workHours", "http://schema.org/workHours" + "workLocation", "http://schema.org/workLocation" + "workPerformed", "http://schema.org/workPerformed" + "workPresented", "http://schema.org/workPresented" + "workTranslation", "http://schema.org/workTranslation" + "workload", "http://schema.org/workload" + "worksFor", "http://schema.org/worksFor" + "worstRating", "http://schema.org/worstRating" + "xpath", "http://schema.org/xpath" + "yearBuilt", "http://schema.org/yearBuilt" + "yearlyRevenue", "http://schema.org/yearlyRevenue" + "yearsInOperation", "http://schema.org/yearsInOperation" + "yield", "http://schema.org/yield" + "File", "http://schema.org/MediaObject" + "path", "http://schema.org/contentUrl" + "Journal", "http://schema.org/Periodical" + "cite-as", "https,//www.w3.org/ns/iana/link-relations/relation#cite-as" + "hasFile", "http://pcdm.org/models#hasFile" + "hasMember", "http://pcdm.org/models#hasMember" + "RepositoryCollection", "http://pcdm.org/models#Collection" + "RepositoryObject", "http://pcdm.org/models#Object" + "ComputationalWorkflow", "https,//bioschemas.org/ComputationalWorkflow" + "input", "https,//bioschemas.org/ComputationalWorkflow#input" + "output", "https,//bioschemas.org/ComputationalWorkflow#output" + "FormalParameter", "https,//bioschemas.org/FormalParameter" + "funding", "http://schema.org/funding" + "wasDerivedFrom", "http://www.w3.org/ns/prov#wasDerivedFrom" + "importedFrom", "http://purl.org/pav/importedFrom" + "importedOn", "http://purl.org/pav/importedOn" + "importedBy", "http://purl.org/pav/importedBy" + "retrievedFrom", "http://purl.org/pav/retrievedFrom" + "retrievedOn", "http://purl.org/pav/retrievedOn" + "retrievedBy", "http://purl.org/pav/retrievedBy" + "conformsTo", "http://purl.org/dc/terms/conformsTo" + "pcdm", "http://pcdm.org/models#" + "bibo", "http://purl.org/ontology/bibo/" + "cc", "http://creativecommons.org/ns#" + "dct", "http://purl.org/dc/terms/" + "foaf", "http://xmlns.com/foaf/0.1/" + "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + "rdfa", "http://www.w3.org/ns/rdfa#" + "rdfs", "http://www.w3.org/2000/01/rdf-schema#" + "schema", "http://schema.org/" + "frapo", "http://purl.org/cerif/frapo/" + "rel", "https,//www.w3.org/ns/iana/link-relations/relation#" + "pav", "http://purl.org/pav/" + "prov", "http://www.w3.org/ns/prov#" + "wfdesc", "http://purl.org/ro/wfdesc#" + "wfprov", "http://purl.org/ro/wfprov#" + "roterms", "http://purl.org/ro/roterms#" + "wf4ever", "http://purl.org/ro/wf4ever#" + """ + + [] + let proxy_V1_1 = "https://w3id.org/ro/crate/1.1/context" + + [] + let proxy_V1_2DRAFT = "https://w3id.org/ro/crate/1.2-DRAFT/context" + + let initBioschemasContext() = + let terms = + [ + "Sample","https://bioschemas.org/Sample" + "additionalProperty","http://schema.org/additionalProperty" + "intendedUse","https://bioschemas.org/intendedUse" + "computationalTool","https://bioschemas.org/computationalTool" + "labEquipment","https://bioschemas.org/labEquipment" + "reagent","https://bioschemas.org/reagent" + "LabProtocol","https://bioschemas.org/LabProtocol" + "executesLabProtocol", "https://bioschemas.org/executesLabProtocol" + "parameterValue", "https://bioschemas.org/parameterValue" + "LabProcess","https://bioschemas.org/LabProcess" + ] + let c = LDContext.fromMappingSeq terms + c + + let initV1_1 () = + let terms = + termsV1_1.Split('\n') + |> Array.choose (fun s -> + match s.Trim() with + | "" -> None + | s -> + let a = s.Replace("\"","").Split(',') + Some (a.[0].Trim(), a.[1].Trim()) + ) + let c = LDContext.fromMappingSeq terms + c.Name <- Some proxy_V1_1 + c + + let initV1_2DRAFT () = + let terms = + termsV1_2DRAFT.Split('\n') + |> Array.choose (fun s -> + match s.Trim() with + | "" -> None + | s -> + let a = s.Replace("\"","").Split(',') + Some (a.[0].Trim(), a.[1].Trim()) + ) + let c = LDContext.fromMappingSeq terms + c.Name <- Some proxy_V1_2DRAFT + c \ No newline at end of file diff --git a/src/ROCrate/playground.fsx b/src/ROCrate/playground.fsx index b910c322..7eac0cea 100644 --- a/src/ROCrate/playground.fsx +++ b/src/ROCrate/playground.fsx @@ -2,12 +2,12 @@ open DynamicObj -type ILDObject = +type ILDNode = abstract member SchemaType : string abstract member Id: string abstract member AdditionalType: string option -type LDObject(id:string, schemaType: string, ?additionalType) = +type LDNode(id:string, schemaType: string, ?additionalType) = inherit DynamicObj() let mutable _schemaType = "schema.org/Dataset" @@ -24,16 +24,16 @@ type LDObject(id:string, schemaType: string, ?additionalType) = with get() = _additionalType and set(value) = _additionalType <- value - interface ILDObject with + interface ILDNode with member this.SchemaType = schemaType member this.Id = id member this.AdditionalType = additionalType type Dataset (id: string, ?additionalType: string) = - inherit LDObject(id = id, schemaType = "schema.org/Dataset", ?additionalType = additionalType) + inherit LDNode(id = id, schemaType = "schema.org/Dataset", ?additionalType = additionalType) //interface implementations - interface ILDObject with + interface ILDNode with member this.Id with get () = this.Id member this.SchemaType with get (): string = this.SchemaType member this.AdditionalType with get (): string option = this.AdditionalType diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs index 9beca1c5..965d3216 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fs +++ b/tests/ARCtrl/ARCtrl.Tests.fs @@ -1380,6 +1380,67 @@ let tests_RemoveStudy = }) ] +let tests_ROCrate = + testList "RO-Crate" [ + ftestCase "CanRead_Deprecated" <| fun _ -> + let arc = ARC.fromDeprecatedROCrateJsonString(TestObjects.ROCrate.ArcPrototypeDeprecated.ed123499) + let isa = Expect.wantSome arc.ISA "ARC should contain an ISA part" + let nonDeprecatedARC = ARC.fromROCrateJsonString(TestObjects.ROCrate.ArcPrototype.ed123499) + let nonDeprecatedISA = Expect.wantSome nonDeprecatedARC.ISA "ARC should contain an ISA part" + Expect.equal isa.Identifier nonDeprecatedISA.Identifier "Investigation should have correct identifier" + Expect.equal isa.Title nonDeprecatedISA.Title "Investigation should have correct title" + Expect.equal isa.Description nonDeprecatedISA.Description "Investigation should have correct description" + Expect.sequenceEqual isa.Contacts nonDeprecatedISA.Contacts "Investigation should have correct contacts" + Expect.sequenceEqual isa.Studies nonDeprecatedISA.Studies "Investigation should have correct studies" + Expect.sequenceEqual isa.Assays nonDeprecatedISA.Assays "Investigation should have correct assays" + + ftestCase "CanRead" <| fun _ -> + let arc = ARC.fromROCrateJsonString(TestObjects.ROCrate.ArcPrototype.ed123499) + let isa = Expect.wantSome arc.ISA "ARC should contain an ISA part" + Expect.equal isa.Identifier "ArcPrototype" "Investigation should have correct identifier" + let title = Expect.wantSome isa.Title "Investigation should have title" + Expect.equal title "ArcPrototype" "Investigation should have correct title" + let description = Expect.wantSome isa.Description "Investigation should have description" + Expect.equal description "A prototypic ARC that implements all specification standards accordingly" "Investigation should have correct description" + /// Contacts + Expect.hasLength isa.Contacts 3 "Investigation should have 3 contacts" + let first = isa.Contacts.[0] + let firstName = Expect.wantSome first.FirstName "First contact should have name" + Expect.equal firstName "Timo" "First contact should have correct name" + let lastName = Expect.wantSome first.LastName "First contact should have last name" + Expect.equal lastName "Mühlhaus" "First contact should have correct last name" + Expect.isNone first.MidInitials "First contact should not have middle initials" + let orcid = Expect.wantSome first.ORCID "First contact should have ORCID" + Expect.equal orcid "0000-0003-3925-6778" "First contact should have correct ORCID" + let affiliation = Expect.wantSome first.Affiliation "First contact should have affiliation" + Expect.equal affiliation "RPTU University of Kaiserslautern" "First contact should have correct affiliation" + let address = Expect.wantSome first.Address "First contact should have address" + Expect.equal address "RPTU University of Kaiserslautern, Paul-Ehrlich-Str. 23 , 67663 Kaiserslautern" "First contact should have correct address" + Expect.hasLength first.Roles 1 "First contact should have roles" + let firstRole = first.Roles.[0] + Expect.equal firstRole.NameText "principal investigator" "First contact should have correct role" + /// Studies + Expect.equal isa.StudyCount 2 "ARC should contain 2 studies" + let secondStudy = isa.Studies.[1] + let secondStudyTitle = Expect.wantSome secondStudy.Title "Second study should have title" + Expect.equal secondStudyTitle "Prototype for experimental data" "Second study should have correct title" + let secondStudyDescription = Expect.wantSome secondStudy.Description "Second study should have description" + Expect.equal secondStudyDescription "In this a devised study to have an exemplary experimental material description." "Second study should have correct description" + Expect.isEmpty secondStudy.Contacts "Second study should have no contacts" + Expect.hasLength secondStudy.Tables 2 "Second study should have 2 tables" + let firstTable = secondStudy.Tables.[0] + Expect.equal firstTable.Name "CellCultivation" "First table should have correct name" + Expect.equal firstTable.RowCount 6 "First table should have correct row count" + Expect.equal firstTable.ColumnCount 5 "First table should have correct column count" + let inputCol = Expect.wantSome (firstTable.TryGetInputColumn()) "First table should have input column" + let expectedHeader = CompositeHeader.Input IOType.Source + Expect.equal inputCol.Header expectedHeader "First table input column should have correct header" + let expectedCells = [for i = 1 to 6 do CompositeCell.FreeText $"Source{i}"] + Expect.sequenceEqual inputCol.Cells expectedCells "First table input column should have correct cells" + /// Assays + Expect.equal isa.AssayCount 2 "ARC should contain 2 assays" + ] + let main = testList "ARCtrl" [ @@ -1400,6 +1461,7 @@ let main = testList "ARCtrl" [ tests_RenameStudy tests_RemoveAssay tests_RemoveStudy + tests_ROCrate ] diff --git a/tests/ARCtrl/ARCtrl.Tests.fsproj b/tests/ARCtrl/ARCtrl.Tests.fsproj index b09ddedc..429974eb 100644 --- a/tests/ARCtrl/ARCtrl.Tests.fsproj +++ b/tests/ARCtrl/ARCtrl.Tests.fsproj @@ -6,6 +6,7 @@ false + diff --git a/tests/ARCtrl/Main.fs b/tests/ARCtrl/Main.fs index d307941d..11100380 100644 --- a/tests/ARCtrl/Main.fs +++ b/tests/ARCtrl/Main.fs @@ -3,6 +3,7 @@ module ARCtrl.ARC.Tests open Fable.Pyxpecto let all = testSequenced <| testList "ARCtrl" [ + ARCtrl.ROCrateConversion.Tests.main ARCtrl.CrossAsync.Tests.main ARCtrl.FileSystemHelper.Tests.main ARCtrl.ContractIO.Tests.main diff --git a/tests/ARCtrl/ROCrateConversion.Tests.fs b/tests/ARCtrl/ROCrateConversion.Tests.fs new file mode 100644 index 00000000..656d816f --- /dev/null +++ b/tests/ARCtrl/ROCrateConversion.Tests.fs @@ -0,0 +1,1352 @@ +module ARCtrl.ROCrateConversion.Tests + +open ARCtrl.ROCrate +open ARCtrl +open ARCtrl.Conversion +open ARCtrl.Process +open TestingUtils + +module Helper = + let tableName1 = "Test1" + let tableName2 = "Test2" + let oa_species = OntologyAnnotation("species", "GO", "GO:0123456") + let dt_species = DefinedTerm.create(name = "species", termCode = oa_species.TermAccessionOntobeeUrl) + let oa_chlamy = OntologyAnnotation("Chlamy", "NCBI", "NCBI:0123456") + let dt_chlamy = DefinedTerm.create(name = "Chlamy", termCode = oa_chlamy.TermAccessionOntobeeUrl) + let oa_instrumentModel = OntologyAnnotation("instrument model", "MS", "MS:0123456") + let dt_instrumentModel = DefinedTerm.create(name = "instrument model", termCode = oa_instrumentModel.TermAccessionOntobeeUrl) + let oa_SCIEXInstrumentModel = OntologyAnnotation("SCIEX instrument model", "MS", "MS:654321") + let dt_SCIEXInstrumentModel = DefinedTerm.create(name = "SCIEX instrument model", termCode = oa_SCIEXInstrumentModel.TermAccessionOntobeeUrl) + let oa_time = OntologyAnnotation("time", "UO", "UO:0000010") + let dt_time = DefinedTerm.create(name = "time", termCode = oa_time.TermAccessionOntobeeUrl) + let oa_hour = OntologyAnnotation("hour", "UO", "UO:0000032") + let dt_hour = DefinedTerm.create(name = "hour", termCode = oa_hour.TermAccessionOntobeeUrl) + let oa_temperature = OntologyAnnotation("temperature","NCIT","NCIT:0123210") + let dt_temperature = DefinedTerm.create(name = "temperature", termCode = oa_temperature.TermAccessionOntobeeUrl) + let oa_degreeCel = OntologyAnnotation("degree celsius","UO","UO:0000027") + let dt_degreeCel = DefinedTerm.create(name = "degree celsius", termCode = oa_degreeCel.TermAccessionOntobeeUrl) + + /// This function can be used to put ArcTable.Values into a nice format for printing/writing to IO + let tableValues_printable (table:ArcTable) = + [ + for KeyValue((c,r),v) in table.Values do + yield $"({c},{r}) {v}" + ] + + let createCells_FreeText pretext (count) = Array.init count (fun i -> CompositeCell.createFreeText $"{pretext}_{i}") + let createCells_Sciex (count) = Array.init count (fun _ -> CompositeCell.createTerm oa_SCIEXInstrumentModel) + let createCells_chlamy (count) = Array.init count (fun _ -> CompositeCell.createTerm oa_chlamy) + let createCells_DegreeCelsius (count) = Array.init count (fun i -> CompositeCell.createUnitized (string i,oa_degreeCel)) + let createCells_Hour (count) = Array.init count (fun i -> CompositeCell.createUnitized (string i,oa_hour)) + + let singleRowSingleParam = + /// Input [Source] --> Source_0 .. Source_4 + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 1) + CompositeColumn.create(CompositeHeader.Parameter oa_species, createCells_chlamy 1) + CompositeColumn.create(CompositeHeader.Output IOType.Sample, createCells_FreeText "Sample" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let singleRowOutputSource = + /// Input [Source] --> Source_0 .. Source_4 + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 1) + CompositeColumn.create(CompositeHeader.Output IOType.Source, createCells_FreeText "Sample" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let singleRowMixedValues = + /// Input [Source] --> Source_0 .. Source_4 + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 1) + CompositeColumn.create(CompositeHeader.Parameter oa_time, createCells_Hour 1) + CompositeColumn.create(CompositeHeader.Characteristic oa_species, createCells_chlamy 1) + CompositeColumn.create(CompositeHeader.Factor oa_temperature, createCells_DegreeCelsius 1) + CompositeColumn.create(CompositeHeader.Component oa_instrumentModel, createCells_Sciex 1) + CompositeColumn.create(CompositeHeader.Output IOType.Sample, createCells_FreeText "Sample" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let singleRowDataInputWithCharacteristic = + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "RData" 1) + CompositeColumn.create(CompositeHeader.Characteristic oa_species, createCells_chlamy 1) + CompositeColumn.create(CompositeHeader.Output IOType.Data, createCells_FreeText "DData" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let singleRowDataOutputWithFactor = + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "RData" 1) + CompositeColumn.create(CompositeHeader.Factor oa_temperature, createCells_DegreeCelsius 1) + CompositeColumn.create(CompositeHeader.Output IOType.Data, createCells_FreeText "DData" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let twoRowsSameParamValue = + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 2) + CompositeColumn.create(CompositeHeader.Parameter oa_species, createCells_chlamy 2) + CompositeColumn.create(CompositeHeader.Output IOType.Sample, createCells_FreeText "Sample" 2) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let twoRowsDifferentParamValue = + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 2) + CompositeColumn.create(CompositeHeader.Parameter oa_time, createCells_Hour 2) + CompositeColumn.create(CompositeHeader.Output IOType.Sample, createCells_FreeText "Sample" 2) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + let singleRowWithProtocolRef = + let columns = + [| + CompositeColumn.create(CompositeHeader.Input IOType.Source, createCells_FreeText "Source" 1) + CompositeColumn.create(CompositeHeader.ProtocolREF, [|CompositeCell.createFreeText "MyProtocol"|]) + CompositeColumn.create(CompositeHeader.Output IOType.Sample, createCells_FreeText "Sample" 1) + |] + let t = ArcTable.init(tableName1) + t.AddColumns(columns) + t + + /// Creates 5 empty tables + /// + /// Table Names: ["New Table 0"; "New Table 1" .. "New Table 4"] + let create_exampleTables(appendStr:string) = Array.init 5 (fun i -> ArcTable.init($"{appendStr} Table {i}")) + + /// Valid TestAssay with empty tables: + /// + /// Table Names: ["New Table 0"; "New Table 1" .. "New Table 4"] + let create_exampleAssay() = + let assay = ArcAssay("MyAssay") + let sheets = create_exampleTables("My") + sheets |> Array.iter (fun table -> assay.AddTable(table)) + assay + +open Helper + + +let tests_DefinedTerm = + testList "DefinedTerm_Full" [ + let oa = OntologyAnnotation("species", "GO", "GO:0123456") + let dt = BaseTypes.composeDefinedTerm oa + let oa' = BaseTypes.decomposeDefinedTerm dt + Expect.equal oa' oa "OntologyAnnotation should match" + ] + +let private tests_ProcessInput = + testList "ProcessInput" [ + testCase "Source" (fun () -> + let header = CompositeHeader.Input(IOType.Source) + let cell = CompositeCell.createFreeText "MySource" + let input = BaseTypes.composeProcessInput header cell + + Expect.isTrue (Sample.validateSource input) "Should be a valid source" + let name = Sample.getNameAsString input + Expect.equal name "MySource" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessInput input + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Sample" (fun () -> + let header = CompositeHeader.Input(IOType.Sample) + let cell = CompositeCell.createFreeText "MySample" + let input = BaseTypes.composeProcessInput header cell + + Expect.isTrue (Sample.validateSample input) "Should be a valid sample" + let name = Sample.getNameAsString input + Expect.equal name "MySample" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessInput input + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Data_Data" (fun () -> + let header = CompositeHeader.Input(IOType.Data) + let data = Data(name = "MyData", format = "text/csv", selectorFormat = "MySelector") + let cell = CompositeCell.createData data + let input = BaseTypes.composeProcessInput header cell + + Expect.isTrue (File.validate input) "Should be a valid data" + let name = File.getNameAsString input + Expect.equal name "MyData" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessInput input + Expect.equal header header' "Header should match" + data.ID <- Some input.Id + Expect.equal cell cell' "Cell should match" + ) + testCase "Data_Freetext" (fun () -> + let header = CompositeHeader.Input(IOType.Data) + let cell = CompositeCell.createFreeText "MyData" + let input = BaseTypes.composeProcessInput header cell + + Expect.isTrue (File.validate input) "Should be a valid data" + let name = File.getNameAsString input + Expect.equal name "MyData" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessInput input + let expectedCell = CompositeCell.createData (Data (id = input.Id, name = "MyData")) + Expect.equal header header' "Header should match" + Expect.equal expectedCell cell' "Cell should match" + ) + testCase "Material" (fun () -> + let header = CompositeHeader.Input(IOType.Material) + let cell = CompositeCell.createFreeText "MyMaterial" + let input = BaseTypes.composeProcessInput header cell + + Expect.isTrue (Sample.validateMaterial input) "Should be a valid material" + let name = Sample.getNameAsString input + Expect.equal name "MyMaterial" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessInput input + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "FreeType" (fun () -> + let header = CompositeHeader.Input (IOType.FreeText "MyInputType") + let cell = CompositeCell.createFreeText "MyFreeText" + let input = BaseTypes.composeProcessInput header cell + + let name = Sample.getNameAsString input + Expect.equal name "MyFreeText" "Name should match" + + let schemaType = input.SchemaType + Expect.hasLength schemaType 1 "Should have 1 schema type" + Expect.equal schemaType.[0] "MyInputType" "Schema type should be FreeText" + + let header',cell' = BaseTypes.decomposeProcessInput input + Expect.equal header header' "Header should match" + ) + ] + +let private tests_ProcessOutput = + testList "ProcessOutput" [ + testCase "Sample" (fun () -> + let header = CompositeHeader.Output(IOType.Sample) + let cell = CompositeCell.createFreeText "MySample" + let output = BaseTypes.composeProcessOutput header cell + + Expect.isTrue (Sample.validateSample output) "Should be a valid sample" + let name = Sample.getNameAsString output + Expect.equal name "MySample" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessOutput output + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Data_Data" (fun () -> + let header = CompositeHeader.Output(IOType.Data) + let data = Data(name = "MyData", format = "text/csv", selectorFormat = "MySelector") + let cell = CompositeCell.createData data + let output = BaseTypes.composeProcessOutput header cell + + Expect.isTrue (File.validate output) "Should be a valid data" + let name = File.getNameAsString output + Expect.equal name "MyData" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessOutput output + Expect.equal header header' "Header should match" + data.ID <- Some output.Id + Expect.equal cell cell' "Cell should match" + ) + testCase "Data_Freetext" (fun () -> + let header = CompositeHeader.Output(IOType.Data) + let cell = CompositeCell.createFreeText "MyData" + let output = BaseTypes.composeProcessOutput header cell + + Expect.isTrue (File.validate output) "Should be a valid data" + let name = File.getNameAsString output + Expect.equal name "MyData" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessOutput output + let expectedCell = CompositeCell.createData (Data (id = output.Id, name = "MyData")) + Expect.equal header header' "Header should match" + Expect.equal expectedCell cell' "Cell should match" + ) + testCase "Material" (fun () -> + let header = CompositeHeader.Output(IOType.Material) + let cell = CompositeCell.createFreeText "MyMaterial" + let output = BaseTypes.composeProcessOutput header cell + + Expect.isTrue (Sample.validateMaterial output) "Should be a valid material" + let name = Sample.getNameAsString output + Expect.equal name "MyMaterial" "Name should match" + + let header',cell' = BaseTypes.decomposeProcessOutput output + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "FreeType" (fun () -> + let header = CompositeHeader.Output (IOType.FreeText "MyOutputType") + let cell = CompositeCell.createFreeText "MyFreeText" + let output = BaseTypes.composeProcessOutput header cell + + let name = Sample.getNameAsString output + Expect.equal name "MyFreeText" "Name should match" + + let schemaType = output.SchemaType + Expect.hasLength schemaType 1 "Should have 1 schema type" + Expect.equal schemaType.[0] "MyOutputType" "Schema type should be FreeText" + + let header',cell' = BaseTypes.decomposeProcessOutput output + Expect.equal header header' "Header should match" + ) + ] + +let private tests_PropertyValue = + testList "PropertyValue" [ + testCase "Characteristic_Ontology" (fun () -> + let header = CompositeHeader.Characteristic oa_species + let cell = CompositeCell.createTerm oa_chlamy + let pv = BaseTypes.composeCharacteristicValue header cell + + let name = PropertyValue.getNameAsString pv + Expect.equal name oa_species.NameText "Name should match" + + let value = PropertyValue.getValueAsString pv + Expect.equal value oa_chlamy.NameText "Value should match" + + let propertyID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString pv) "Should have property ID" + Expect.equal propertyID oa_species.TermAccessionOntobeeUrl "Property ID should match" + + let valueReference = Expect.wantSome (PropertyValue.tryGetValueReference pv) "Should have value reference" + Expect.equal valueReference oa_chlamy.TermAccessionOntobeeUrl "Value reference should match" + + let header',cell' = BaseTypes.decomposeCharacteristicValue pv + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Parameter_Unitized" (fun () -> + let header = CompositeHeader.Parameter oa_temperature + let cell = CompositeCell.createUnitized ("5",oa_degreeCel) + let pv = BaseTypes.composeParameterValue header cell + + let name = PropertyValue.getNameAsString pv + Expect.equal name oa_temperature.NameText "Name should match" + + let value = PropertyValue.getValueAsString pv + Expect.equal value "5" "Value should match" + + let propertyID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString pv) "Should have property ID" + Expect.equal propertyID oa_temperature.TermAccessionOntobeeUrl "Property ID should match" + + let unit = Expect.wantSome (PropertyValue.tryGetUnitTextAsString pv) "Should have unit" + Expect.equal unit oa_degreeCel.NameText "Unit should match" + + let unitCode = Expect.wantSome (PropertyValue.tryGetUnitCodeAsString pv) "Should have unit code" + Expect.equal unitCode oa_degreeCel.TermAccessionOntobeeUrl "Unit code should match" + + let header',cell' = BaseTypes.decomposeParameterValue pv + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Parameter_Unitized_Valueless" (fun () -> + let header = CompositeHeader.Parameter oa_temperature + let cell = CompositeCell.createUnitized ("",oa_degreeCel) + let pv = BaseTypes.composeParameterValue header cell + + let name = PropertyValue.getNameAsString pv + Expect.equal name oa_temperature.NameText "Name should match" + + Expect.isNone (PropertyValue.tryGetValueAsString pv) "Should not have value" + + let propertyID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString pv) "Should have property ID" + Expect.equal propertyID oa_temperature.TermAccessionOntobeeUrl "Property ID should match" + + let unit = Expect.wantSome (PropertyValue.tryGetUnitTextAsString pv) "Should have unit" + Expect.equal unit oa_degreeCel.NameText "Unit should match" + + let unitCode = Expect.wantSome (PropertyValue.tryGetUnitCodeAsString pv) "Should have unit code" + Expect.equal unitCode oa_degreeCel.TermAccessionOntobeeUrl "Unit code should match" + + let header',cell' = BaseTypes.decomposeParameterValue pv + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "FactorValue_Valueless" (fun () -> + let header = CompositeHeader.Factor oa_temperature + let cell = CompositeCell.createTerm (OntologyAnnotation.create()) + let pv = BaseTypes.composeFactorValue header cell + + let name = PropertyValue.getNameAsString pv + Expect.equal name oa_temperature.NameText "Name should match" + + let propertyID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString pv) "Should have property ID" + Expect.equal propertyID oa_temperature.TermAccessionOntobeeUrl "Property ID should match" + + Expect.isNone (PropertyValue.tryGetValueAsString pv) "Should not have value" + + let header',cell' = BaseTypes.decomposeFactorValue pv + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + testCase "Component_Freetexts" (fun () -> + let header = CompositeHeader.Component (OntologyAnnotation.create(name = "MyComponentHeader")) + let cell = CompositeCell.createTerm (OntologyAnnotation.create(name = "MyComponentValue")) + let pv = BaseTypes.composeComponent header cell + + let name = PropertyValue.getNameAsString pv + Expect.equal name "MyComponentHeader" "Name should match" + + let value = PropertyValue.getValueAsString pv + Expect.equal value "MyComponentValue" "Value should match" + + Expect.isNone (PropertyValue.tryGetPropertyIDAsString pv) "Should not have property ID" + Expect.isNone (PropertyValue.tryGetValueReference pv) "Should not have value reference" + Expect.isNone (PropertyValue.tryGetUnitTextAsString pv) "Should not have unit" + Expect.isNone (PropertyValue.tryGetUnitCodeAsString pv) "Should not have unit code" + + let header',cell' = BaseTypes.decomposeComponent pv + Expect.equal header header' "Header should match" + Expect.equal cell cell' "Cell should match" + ) + ] + + +let private tests_ArcTableProcess = + testList "ARCTableProcess" [ + testCase "SingleRowSingleParam GetProcesses" (fun () -> + let t = singleRowSingleParam.Copy() + let processes = t.GetProcesses() + let expectedPPV = + PropertyValue.createParameterValue( + name = oa_species.NameText, + value = oa_chlamy.NameText, + propertyID = oa_species.TermAccessionOntobeeUrl, + valueReference = oa_chlamy.TermAccessionOntobeeUrl + ) + ColumnIndex.setIndex expectedPPV 0 + let expectedInput = Sample.createSource(name = "Source_0") + let expectedOutput = Sample.createSample(name = "Sample_0") + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let paramValues = LabProcess.getParameterValues(p) + Expect.equal paramValues.Count 1 "Process should have 1 parameter values" + Expect.equal paramValues.[0] expectedPPV "Param value does not match" + let inputs = LabProcess.getObjects(p) + Expect.equal inputs.Count 1 "Process should have 1 input" + Expect.equal inputs.[0] expectedInput "Input value does not match" + let outputs = LabProcess.getResults(p) + Expect.equal outputs.Count 1 "Process should have 1 output" + Expect.equal outputs.[0] expectedOutput "Output value does not match" + let name = LabProcess.getNameAsString p + Expect.equal name tableName1 "Process name should match table name" + ) + testCase "SingleRowSingleParam GetAndFromProcesses" (fun () -> + let t = singleRowSingleParam.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + testCase "SingleRowOutputSource GetProcesses" (fun () -> + let t = singleRowOutputSource.Copy() + let processes = t.GetProcesses() + let expectedInput = Sample.createSource(name = "Source_0") + let expectedOutput = Sample.createSample(name = "Sample_0") + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let inputs = LabProcess.getObjects(p) + Expect.equal inputs.Count 1 "Process should have 1 input" + Expect.equal inputs.[0] expectedInput "Input value does not match" + let outputs = LabProcess.getResults(p) + Expect.equal outputs.Count 1 "Process should have 1 output" + Expect.equal outputs.[0] expectedOutput "Output value does not match" + let name = LabProcess.getNameAsString p + Expect.equal name tableName1 "Process name should match table name" + ) + + testCase "SingleRowMixedValues GetProcesses" (fun () -> + let t = singleRowMixedValues.Copy() + let processes = t.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + Expect.equal (LabProcess.getParameterValues processes.[0]).Count 1 "Process should have 1 parameter values" + let input = Expect.wantSome ((LabProcess.getObjects processes.[0]) |> Seq.tryExactlyOne) "Process should have 1 input" + let output = Expect.wantSome ((LabProcess.getResults processes.[0]) |> Seq.tryExactlyOne) "Process should have 1 output" + let charas = Sample.getCharacteristics input + Expect.hasLength charas 1 "Input should have the charactersitic" + let factors = Sample.getFactors output + Expect.hasLength factors 1 "Output should have the factor value" + ) + + testCase "SingleRowMixedValues GetAndFromProcesses" (fun () -> + let t = singleRowMixedValues.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + testCase "SingleRowDataInputWithCharacteristic GetProcesses" (fun () -> + let t = singleRowDataInputWithCharacteristic.Copy() + let processes = t.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let inputs = LabProcess.getObjects(p) + Expect.equal inputs.Count 1 "Process should have 1 input" + let outputs = LabProcess.getResults(p) + Expect.equal outputs.Count 1 "Process should have 1 output" + Expect.isTrue (File.validate(inputs.[0])) "First input should be data" + let charas = Sample.getCharacteristics(inputs.[0]) + Expect.hasLength charas 1 "Input should have the charactersitic" + ) + + testCase "SingleRowDataInputWithCharacteristic GetAndFromProcesses" (fun () -> + let t = singleRowDataInputWithCharacteristic.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + let expectedInputData = CompositeCell.Data(Data(id = "RData_0", name = "RData_0")) + let expectedOutputData = CompositeCell.Data(Data(id = "DData_0", name = "DData_0")) + expectedTable.SetCellAt(0,0,expectedInputData) + expectedTable.SetCellAt(t.ColumnCount - 1,0,expectedOutputData) + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + testCase "SingleRowDataOutputWithFactor GetProcesses" (fun () -> + let t = singleRowDataOutputWithFactor.Copy() + let processes = t.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let inputs = LabProcess.getObjects(p) + Expect.equal inputs.Count 1 "Process should have 1 input" + Expect.isTrue (File.validate inputs.[0]) "input should be data" + let outputs = LabProcess.getResults(p) + Expect.equal outputs.Count 1 "Process should have 1 output" + Expect.isTrue (File.validate outputs.[0]) "output should be data" + let factors = Sample.getFactors(outputs.[0]) + Expect.hasLength factors 1 "output should have 1 factor value" + ) + + testCase "SingleRowDataOutputWithFactor GetAndFromProcesses" (fun () -> + let t = singleRowDataOutputWithFactor.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + let expectedInputData = CompositeCell.Data(Data(id = "RData_0", name = "RData_0")) + let expectedOutputData = CompositeCell.Data(Data(id = "DData_0", name = "DData_0")) + expectedTable.SetCellAt(0,0,expectedInputData) + expectedTable.SetCellAt(t.ColumnCount - 1,0,expectedOutputData) + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + testCase "TwoRowsSameParamValue GetAndFromProcesses" (fun () -> + let t = twoRowsSameParamValue.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + testCase "TwoRowsDifferentParamValues GetProcesses" (fun () -> + let t = twoRowsDifferentParamValue.Copy() + let processes = t.GetProcesses() + Expect.equal processes.Length 2 "Should have 2 processes" + ) + + testCase "TwoRowsDifferentParamValues GetAndFromProcesses" (fun () -> + let t = twoRowsDifferentParamValue.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + testCase "SingleRowWithProtocolREF GetProcesses" (fun () -> + let t = singleRowWithProtocolRef.Copy() + let processes = t.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let prot = Expect.wantSome (LabProcess.tryGetExecutesLabProtocol(p)) "Process should have protocol" + let protName = Expect.wantSome (LabProtocol.tryGetNameAsString(prot)) "Protocol should have name" + Expect.equal protName "MyProtocol" "Protocol name should match" + let pName = Expect.wantSome (LabProcess.tryGetNameAsString(p)) "Process should have name" + Expect.equal pName tableName1 "Process name should match table name" + ) + + testCase "SingleRowWithProtocolREF GetAndFromProcesses" (fun () -> + let t = singleRowWithProtocolRef.Copy() + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual table t "Table should be equal" + ) + + testCase "EmptyTable GetProcesses" (fun () -> + let t = ArcTable.init tableName1 + let processes = t.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let name = LabProcess.getNameAsString p + Expect.equal name tableName1 "Process name should match table name" + Expect.isEmpty (LabProcess.getObjects(p)) "Process should have no inputs" + Expect.isEmpty (LabProcess.getResults(p)) "Process should have no outputs" + Expect.isEmpty (LabProcess.getParameterValues(p)) "Process should have no parameter values" + Expect.isNone (LabProcess.tryGetExecutesLabProtocol(p)) "Process should have no protocol" + ) + + // Currently only checks for function failing which it did in python + testCase "MixedColumns GetProcesses" (fun () -> + let table = + TestObjects.Spreadsheet.ArcTable.initWorksheet "SheetName" + [ + TestObjects.Spreadsheet.ArcTable.Protocol.REF.appendLolColumn 4 + TestObjects.Spreadsheet.ArcTable.Protocol.Type.appendCollectionColumn 2 + TestObjects.Spreadsheet.ArcTable.Parameter.appendMixedTemperatureColumn 2 2 + TestObjects.Spreadsheet.ArcTable.Parameter.appendInstrumentColumn 2 + TestObjects.Spreadsheet.ArcTable.Characteristic.appendOrganismColumn 3 + TestObjects.Spreadsheet.ArcTable.Factor.appendTimeColumn 0 + ] + |> Spreadsheet.ArcTable.tryFromFsWorksheet + table.Value.GetProcesses() |> ignore + Expect.isTrue true "" + ) + + testCase "EmptyTable GetAndFromProcesses" (fun () -> + let t = ArcTable.init tableName1 + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual table t "Table should be equal" + ) + testCase "OnlyInput GetAndFromProcessess" (fun () -> + let t = ArcTable.init tableName1 + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + let processes = t.GetProcesses() + let table = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual table t "Table should be equal" + ) + testCase "ParamValueUnitizedNoValueNoInputOutput" (fun () -> + let t = ArcTable.init tableName1 + let header = CompositeHeader.Parameter oa_temperature + let unit = oa_degreeCel + let cell = CompositeCell.createUnitized ("",unit) + t.AddColumn(header,[|cell|]) + + let processes = t.GetProcesses() + Expect.equal 1 processes.Length "Should have 1 process" + let p = processes.[0] + let pvs = LabProcess.getParameterValues p + Expect.hasLength pvs 1 "Should have 1 parameter value" + let pv = pvs.[0] + Expect.isNone (PropertyValue.tryGetValueAsString(pv)) "Should have no value" + let categoryName = Expect.wantSome (PropertyValue.tryGetNameAsString(pv)) "Should have category name" + Expect.equal categoryName oa_temperature.NameText "Category name should match" + let categoryID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString(pv)) "Should have category ID" + Expect.equal categoryID oa_temperature.TermAccessionOntobeeUrl "Category ID should match" + let unitName = Expect.wantSome (PropertyValue.tryGetUnitTextAsString(pv)) "Should have unit name" + Expect.equal unitName oa_degreeCel.NameText "Unit name should match" + let unitCode = Expect.wantSome (PropertyValue.tryGetUnitCodeAsString(pv)) "Should have unit code" + Expect.equal unitCode oa_degreeCel.TermAccessionOntobeeUrl "Unit code should match" + + let t' = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual t' t "Table should be equal" + ) + testCase "ParamValueUnitizedNoValue" (fun () -> + let t = ArcTable.init tableName1 + let header = CompositeHeader.Parameter oa_temperature + let unit = oa_degreeCel + let cell = CompositeCell.createUnitized ("",unit) + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + t.AddColumn(header,[|cell|]) + t.AddColumn(CompositeHeader.Output(IOType.Sample),[|CompositeCell.createFreeText "Sample"|]) + + let processes = t.GetProcesses() + Expect.equal 1 processes.Length "Should have 1 process" + let p = processes.[0] + + let pvs = LabProcess.getParameterValues p + Expect.hasLength pvs 1 "Should have 1 parameter value" + let pv = pvs.[0] + Expect.isNone (PropertyValue.tryGetValueAsString(pv)) "Should have no value" + let categoryName = Expect.wantSome (PropertyValue.tryGetNameAsString(pv)) "Should have category name" + Expect.equal categoryName oa_temperature.NameText "Category name should match" + let categoryID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString(pv)) "Should have category ID" + Expect.equal categoryID oa_temperature.TermAccessionOntobeeUrl "Category ID should match" + let unitName = Expect.wantSome (PropertyValue.tryGetUnitTextAsString(pv)) "Should have unit name" + Expect.equal unitName oa_degreeCel.NameText "Unit name should match" + let unitCode = Expect.wantSome (PropertyValue.tryGetUnitCodeAsString(pv)) "Should have unit code" + Expect.equal unitCode oa_degreeCel.TermAccessionOntobeeUrl "Unit code should match" + + let t' = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual t' t "Table should be equal" + ) + ptestCase "ParamValueUnitizedEmpty" (fun () -> + let t = ArcTable.init tableName1 + let header = CompositeHeader.Parameter oa_temperature + let cell = CompositeCell.createUnitized ("") + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + t.AddColumn(header,[|cell|]) + t.AddColumn(CompositeHeader.Output(IOType.Sample),[|CompositeCell.createFreeText "Sample"|]) + + let processes = t.GetProcesses() + Expect.equal 1 processes.Length "Should have 1 process" + let p = processes.[0] + let pvs = LabProcess.getParameterValues p + Expect.hasLength pvs 1 "Should have 1 parameter value" + let pv = pvs.[0] + Expect.isNone (PropertyValue.tryGetValueAsString(pv)) "Should have no value" + let categoryName = Expect.wantSome (PropertyValue.tryGetNameAsString(pv)) "Should have category name" + Expect.equal categoryName oa_temperature.NameText "Category name should match" + let categoryID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString(pv)) "Should have category ID" + Expect.equal categoryID oa_temperature.TermAccessionOntobeeUrl "Category ID should match" + Expect.isNone (PropertyValue.tryGetUnitTextAsString(pv)) "Should have no unit text" + Expect.isNone (PropertyValue.tryGetUnitCodeAsString(pv)) "Should have no unit code" + + let t' = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual t' t "Table should be equal" + ) + ptestCase "ParamValueUnitizedNoUnit" (fun () -> + let t = ArcTable.init tableName1 + let header = CompositeHeader.Parameter oa_temperature + let cell = CompositeCell.createUnitized ("5") + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + t.AddColumn(header,[|cell|]) + t.AddColumn(CompositeHeader.Output(IOType.Sample),[|CompositeCell.createFreeText "Sample"|]) + + let processes = t.GetProcesses() + Expect.equal 1 processes.Length "Should have 1 process" + let p = processes.[0] + let pvs = LabProcess.getParameterValues p + Expect.hasLength pvs 1 "Should have 1 parameter value" + let pv = pvs.[0] + let categoryName = Expect.wantSome (PropertyValue.tryGetNameAsString(pv)) "Should have category name" + Expect.equal categoryName oa_temperature.NameText "Category name should match" + let categoryID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString(pv)) "Should have category ID" + Expect.equal categoryID oa_temperature.TermAccessionOntobeeUrl "Category ID should match" + let value = Expect.wantSome (PropertyValue.tryGetValueAsString(pv)) "Should have value" + Expect.equal value "5" "Value should match" + Expect.isNone (PropertyValue.tryGetUnitTextAsString(pv)) "Should have no unit text" + Expect.isNone (PropertyValue.tryGetUnitCodeAsString(pv)) "Should have no unit code" + + let t' = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual t' t "Table should be equal" + ) + testCase "ParamValueTermEmpty" (fun () -> + let t = ArcTable.init tableName1 + let header = CompositeHeader.Parameter oa_species + let cell = CompositeCell.createTerm (OntologyAnnotation.create()) + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + t.AddColumn(header,[|cell|]) + t.AddColumn(CompositeHeader.Output(IOType.Sample),[|CompositeCell.createFreeText "Sample"|]) + + let processes = t.GetProcesses() + Expect.equal 1 processes.Length "Should have 1 process" + let p = processes.[0] + let pvs = LabProcess.getParameterValues p + Expect.hasLength pvs 1 "Should have 1 parameter value" + let pv = pvs.[0] + let categoryName = Expect.wantSome (PropertyValue.tryGetNameAsString(pv)) "Should have category name" + Expect.equal categoryName oa_species.NameText "Category name should match" + let categoryID = Expect.wantSome (PropertyValue.tryGetPropertyIDAsString(pv)) "Should have category ID" + Expect.equal categoryID oa_species.TermAccessionOntobeeUrl "Category ID should match" + Expect.isNone (PropertyValue.tryGetValueAsString(pv)) "Should have no value" + Expect.isNone (PropertyValue.tryGetUnitTextAsString(pv)) "Should have no unit text" + Expect.isNone (PropertyValue.tryGetUnitCodeAsString(pv)) "Should have no unit code" + + let t' = ArcTable.fromProcesses(tableName1,processes) + Expect.arcTableEqual t' t "Table should be equal" + ) + testCase "SingleRowIOAndComment GetAndFromProcesses" (fun () -> + let t = ArcTable.init(tableName1) + let commentKey = "MyCommentKey" + let commentValue = "MyCommentValue" + t.AddColumn(CompositeHeader.Input(IOType.Source),[|CompositeCell.createFreeText "Source"|]) + t.AddColumn(CompositeHeader.Comment(commentKey), [|CompositeCell.createFreeText commentValue|]) + t.AddColumn(CompositeHeader.Output(IOType.Sample),[|CompositeCell.createFreeText "Sample"|]) + let processes = t.GetProcesses() + Expect.hasLength processes 1 "Should have 1 process" + let comments = LabProcess.getDisambiguatingDescriptionsAsString(processes.[0]) + Expect.hasLength comments 1 "Should have 1 comment" + let comment = Comment.fromString comments.[0] + Expect.equal comment (Comment(commentKey,commentValue)) "" + let table = ArcTable.fromProcesses(tableName1,processes) + let expectedTable = t + Expect.arcTableEqual table expectedTable "Table should be equal" + ) + + ] + +let private tests_ArcTablesProcessSeq = + testList "ARCTablesProcessSeq" [ + testCase "NoTables GetProcesses" (fun () -> + let t = ArcTables(ResizeArray()) + let processes = t.GetProcesses() + Expect.equal processes.Length 0 "Should have 0 processes" + ) + testCase "NoTables GetAndFromProcesses" (fun () -> + let t = ArcTables(ResizeArray()) + let processes = t.GetProcesses() + let resultTables = ArcTables.fromProcesses processes + Expect.equal resultTables.TableCount 0 "Should have 0 tables" + ) + + testCase "EmptyTable GetProcesses" (fun () -> + let t = ArcTable.init tableName1 + let tables = ArcTables(ResizeArray([t])) + let processes = tables.GetProcesses() + Expect.equal processes.Length 1 "Should have 1 process" + let p = processes.[0] + let name = LabProcess.getNameAsString p + Expect.equal name tableName1 "Process name should match table name" + Expect.isEmpty (LabProcess.getObjects(p)) "Process should have no inputs" + Expect.isEmpty (LabProcess.getResults(p)) "Process should have no outputs" + Expect.isEmpty (LabProcess.getParameterValues(p)) "Process should have no parameter values" + Expect.isNone (LabProcess.tryGetExecutesLabProtocol(p)) "Process should have no protocol" + ) + + testCase "EmptyTable GetAndFromProcesses" (fun () -> + let t = ArcTable.init tableName1 + let tables = ArcTables(ResizeArray([t])) + let processes = tables.GetProcesses() + let table = ArcTables.fromProcesses processes + Expect.equal table.TableCount 1 "Should have 1 table" + Expect.arcTableEqual table.Tables.[0] t "Table should be equal" + ) + + testCase "SimpleTables GetAndFromProcesses" (fun () -> + let t1 = singleRowSingleParam.Copy() + let t2 = + singleRowSingleParam.Copy() |> fun t -> ArcTable.create(tableName2, t.Headers, t.Values) + let tables = ResizeArray[t1;t2] |> ArcTables + let processes = tables.GetProcesses() + Expect.equal processes.Length 2 "Should have 2 processes" + let resultTables = ArcTables.fromProcesses processes + + let expectedTables = [ t1;t2 ] + + Expect.equal resultTables.TableCount 2 "2 Tables should have been created" + Expect.arcTableEqual resultTables.Tables.[0] expectedTables.[0] "Table 1 should be equal" + Expect.arcTableEqual resultTables.Tables.[1] expectedTables.[1] "Table 2 should be equal" + + ) + testCase "OneWithDifferentParamVals GetAndFromProcesses" (fun () -> + let t1 = singleRowSingleParam.Copy() + let t2 = + twoRowsDifferentParamValue.Copy() |> fun t -> ArcTable.create(tableName2, t.Headers, t.Values) + let tables = ResizeArray[t1;t2] |> ArcTables + let processes = tables.GetProcesses() + Expect.equal processes.Length 3 "Should have 3 processes" + let resultTables = ArcTables.fromProcesses processes + + let expectedTables = + [ + t1 + t2 + ] + + Expect.equal resultTables.TableCount 2 "2 Tables should have been created" + Expect.arcTableEqual resultTables.Tables.[0] expectedTables.[0] "Table 1 should be equal" + Expect.arcTableEqual resultTables.Tables.[1] expectedTables.[1] "Table 2 should be equal" + ) + ] + + +//let private tests_ProtocolTransformation = + +// let pName = "ProtocolName" +// let pType = OntologyAnnotation("Growth","ABC","ABC:123") +// let pVersion = "1.0" +// let pDescription = "Great Protocol" + +// let pParam1OA = OntologyAnnotation("Temperature","NCIT","NCIT:123") +// let pParam1 = PropertyValue.createParameterValue(name = "Growth") + +// //LabProtocol.crea + +// testList "Protocol Transformation" [ +// testCase "FromProtocol Empty" (fun () -> +// let p = LabProtocol.create(id = Identifier.createMissingIdentifier()) +// let t = p |> ArcTable.fromProtocol + +// Expect.equal t.ColumnCount 0 "ColumnCount should be 0" +// Expect.isTrue (Identifier.isMissingIdentifier t.Name) $"Name should be missing identifier, not \"{t.Name}\"" +// ) +// testCase "FromProtocol SingleParameter" (fun () -> +// let p = LabProtocol.create(id = Identifier.createMissingIdentifier())(Parameters = [pParam1]) +// let t = p |> ArcTable.fromProtocol + +// Expect.equal t.ColumnCount 1 "ColumnCount should be 1" +// let c = t.TryGetCellAt(0,0) +// Expect.isNone c "Cell should not exist" +// ) +// testCase "FromProtocol SingleProtocolType" (fun () -> +// let p = Protocol.create(ProtocolType = pType) +// let t = p |> ArcTable.fromProtocol +// let expected = CompositeCell.Term pType + +// Expect.equal t.ColumnCount 1 "ColumnCount should be 1" +// let c = t.TryGetCellAt(0,0) +// Expect.isSome c "Cell should exist" +// let c = c.Value +// Expect.equal c expected "Cell value does not match" +// ) +// testCase "FromProtocol SingleName" (fun () -> +// let p = Protocol.create(Name = pName) +// let t = p |> ArcTable.fromProtocol +// let expected = CompositeCell.FreeText pName + +// Expect.equal t.ColumnCount 1 "ColumnCount should be 1" +// let c = t.TryGetCellAt(0,0) +// Expect.isSome c "Cell should exist" +// let c = c.Value +// Expect.equal c expected "Cell value does not match" +// ) +// testCase "FromProtocol SingleVersion" (fun () -> +// let p = Protocol.create(Version = pVersion) +// let t = p |> ArcTable.fromProtocol +// let expected = CompositeCell.FreeText pVersion + +// Expect.equal t.ColumnCount 1 "ColumnCount should be 1" +// let c = t.TryGetCellAt(0,0) +// Expect.isSome c "Cell should exist" +// let c = c.Value +// Expect.equal c expected "Cell value does not match" +// ) +// testCase "FromProtocol SingleDescription" (fun () -> +// let p = Protocol.create(Description = pDescription) +// let t = p |> ArcTable.fromProtocol +// let expected = CompositeCell.FreeText pDescription + +// Expect.equal t.ColumnCount 1 "ColumnCount should be 1" +// let c = t.TryGetCellAt(0,0) +// Expect.isSome c "Cell should exist" +// let c = c.Value +// Expect.equal c expected "Cell value does not match" +// ) +// testCase "GetProtocols NoName" (fun () -> +// let t = ArcTable.init "TestTable" +// let expected = [Protocol.create(Name = "TestTable")] + +// TestingUtils.Expect.sequenceEqual (t.GetProtocols()) expected "Protocol Name should be ArcTable name." +// ) +// testCase "GetProtocols SingleName" (fun () -> +// let t = ArcTable.init "TestTable" +// let name = "Name" +// t.AddProtocolNameColumn([|name|]) +// let expected = [Protocol.create(Name = name)] + +// TestingUtils.Expect.sequenceEqual (t.GetProtocols()) expected "Protocols do not match" +// ) +// testCase "GetProtocols SameNames" (fun () -> +// let t = ArcTable.init "TestTable" +// let name = "Name" +// t.AddProtocolNameColumn([|name;name|]) +// let expected = [Protocol.create(Name = name)] + +// TestingUtils.Expect.sequenceEqual (t.GetProtocols()) expected "Protocols do not match" +// ) +// testCase "GetProtocols DifferentNames" (fun () -> +// let t = ArcTable.init "TestTable" +// let name1 = "Name" +// let name2 = "Name2" +// t.AddProtocolNameColumn([|name1;name2|]) +// let expected = [Protocol.create(Name = name1);Protocol.create(Name = name2)] + +// TestingUtils.Expect.sequenceEqual (t.GetProtocols()) expected "Protocols do not match" +// ) + //testCase "GetProtocols Parameters" (fun () -> + // let t = ArcTable.init "TestTable" + // let name1 = "Name" + // let name2 = "Name2" + // t.AddProtocolNameColumn([|name1;name2|]) + // t.addpara([|pParam1;pParam1|]) + // let expected = [Protocol.create(Name = name1;Parameters = [pParam1]);Protocol.create(Name = name2;Parameters = [pParam1])] + // TestingUtils.Expect.sequenceEqual (t.GetProtocols()) expected "Protocols do not match" + + //) + + + //] + + +let tests_Person = + testList "Person" [ + testCase "Full_FromScaffold" (fun () -> + let role = OntologyAnnotation(name = "Resarcher", tsr = "oo", tan = "oo:123") + let p = ARCtrl.Person(orcid = "0000-0002-1825-0097", firstName = "John", lastName = "Doe", midInitials = "BD", email = "jd@email.com", phone = "123", fax = "456", address = "123 Main St", affiliation = "My University",roles = ResizeArray [role]) + let ro_Person = PersonConversion.composePerson p + let p' = PersonConversion.decomposePerson ro_Person + Expect.equal p' p "Person should match" + ) + testCase "Full_FromScaffold_Flattened" (fun () -> + let role = OntologyAnnotation(name = "Resarcher", tsr = "oo", tan = "oo:123") + let p = ARCtrl.Person(orcid = "0000-0002-1825-0097", firstName = "John", lastName = "Doe", midInitials = "BD", email = "jd@email.com", phone = "123", fax = "456", address = "123 Main St", affiliation = "My University",roles = ResizeArray [role]) + let ro_Person = PersonConversion.composePerson p + let graph = ro_Person.Flatten() + // Test that flattened worked + Expect.isTrue (graph.Nodes.Count > 0) "Graph should have properties" + let roleRef = Expect.wantSome (ro_Person.TryGetPropertyAsSingleton(Person.jobTitle)) "Person should still have jobTitle" + Expect.isTrue (roleRef :? LDRef) "Person should be flattened correctly" + // + let p' = PersonConversion.decomposePerson(ro_Person, graph = graph) + Expect.equal p' p "Person should match" + ) + testCase "ORCIDHandling_Number" (fun () -> + let p = ARCtrl.Person(firstName = "MyDude", orcid = "0000-0002-1825-0097") + let ro_Person = PersonConversion.composePerson p + Expect.equal ro_Person.Id "http://orcid.org/0000-0002-1825-0097" "ORCID should be correct" + let p' = PersonConversion.decomposePerson ro_Person + Expect.equal p' p "Person should match" + ) + testCase "ORCIDHandling_URL" (fun () -> + let p = ARCtrl.Person(firstName = "MyDude", orcid = "http://orcid.org/0000-0002-1825-0097") + let ro_Person = PersonConversion.composePerson p + Expect.equal ro_Person.Id "http://orcid.org/0000-0002-1825-0097" "ORCID should be correct" + let p' = PersonConversion.decomposePerson ro_Person + p.ORCID <- Some "0000-0002-1825-0097" + Expect.equal p' p "Person should match" + ) + testCase "AddressAsObject_FromROCrate" (fun () -> + let address = PostalAddress.create(addressCountry = "Germoney", postalCode = "6969", streetAddress = "I think I'm funny street 69") + let p = ARCtrl.ROCrate.Person.create(givenName = "Loooookas",address = address) + let scaffold_Person = PersonConversion.decomposePerson p + let p' = PersonConversion.composePerson scaffold_Person + Expect.equal p' p "Person should match" + ) + testCase "AddressAsString_FromROCrate" (fun () -> + let address = "Germoney, 6969, I think I'm funny street 69" + let p = ARCtrl.ROCrate.Person.create(givenName = "Loooookas",address = address) + let scaffold_Person = PersonConversion.decomposePerson p + let p' = PersonConversion.composePerson scaffold_Person + Expect.equal p' p "Person should match" + ) + testCase "AffiliationOnlyName_FromROCrate" (fun () -> + let affiliation = Organization.create(name = "My University") + let p = ARCtrl.ROCrate.Person.create(givenName = "Loooookas",affiliation = affiliation) + let scaffold_Person = PersonConversion.decomposePerson p + let p' = PersonConversion.composePerson scaffold_Person + Expect.equal p' p "Person should match" + ) + testCase "AffiliationMoreFields_FromROCrate" (fun () -> + let affiliation = Organization.create(name = "My University") + affiliation.SetProperty("address","123 Main St") + let p = ARCtrl.ROCrate.Person.create(givenName = "Loooookas",affiliation = affiliation) + let scaffold_Person = PersonConversion.decomposePerson p + let p' = PersonConversion.composePerson scaffold_Person + Expect.equal p' p "Person should match" + ) + ] + +let tests_Publication = + testList "Publication" [ + testCase "Full_FromScaffold" (fun () -> + let authors = "Lukas Weil, John Doe" + let comment = Comment("MyCommentKey","MyCommentValue") + let commentOnlyKey = Comment("MyEmptyKey") + let status = OntologyAnnotation(name = "Published", tsr = "oo", tan = "oo:123") + let p = ARCtrl.Publication.create(title = "My Paper", doi = "10.1234/5678", authors = authors, status = status, comments = ResizeArray [comment; commentOnlyKey]) + let ro_Publication = ScholarlyArticleConversion.composeScholarlyArticle p + let p' = ScholarlyArticleConversion.decomposeScholarlyArticle ro_Publication + Expect.equal p' p "Publication should match" + ) + testCase "DOI_PubMedID_FromScaffold" (fun () -> + let doi = "10.1234/5678" + let pubMedID = "12345678" + let p = ARCtrl.Publication.create(title = "My Paper", doi = doi, pubMedID = pubMedID) + let ro_Publication = ScholarlyArticleConversion.composeScholarlyArticle p + let p' = ScholarlyArticleConversion.decomposeScholarlyArticle ro_Publication + Expect.equal p' p "Publication should match" + ) + testCase "Full_FromScaffold_Flattened" (fun () -> + let authors = "Lukas Weil, John Doe" + let comment = Comment("MyCommentKey","MyCommentValue") + let commentOnlyKey = Comment("MyEmptyKey") + let status = OntologyAnnotation(name = "Published", tsr = "oo", tan = "oo:123") + let p = ARCtrl.Publication.create(title = "My Paper", doi = "10.1234/5678", authors = authors, status = status, comments = ResizeArray [comment; commentOnlyKey]) + let ro_Publication = ScholarlyArticleConversion.composeScholarlyArticle p + let graph = ro_Publication.Flatten() + // Test that flattened worked + Expect.isTrue (graph.Nodes.Count > 0) "Graph should have properties" + let statusRef = Expect.wantSome (ro_Publication.TryGetPropertyAsSingleton(ScholarlyArticle.creativeWorkStatus)) "Publication should still have status" + Expect.isTrue (statusRef :? LDRef) "Publication should be flattened correctly" + // + let p' = ScholarlyArticleConversion.decomposeScholarlyArticle(ro_Publication,graph = graph) + Expect.equal p' p "Publication should match" + ) + testCase "FullAuthors_FromROCrate" (fun () -> + let author1 = ARCtrl.ROCrate.Person.create(givenName = "Lukas",familyName = "Weil", orcid = "0000-0002-1825-0097") + let author2 = ARCtrl.ROCrate.Person.create(givenName = "John",familyName = "Doe", orcid = "0000-0002-1325-0077") + let scholarlyArticle = ARCtrl.ROCrate.ScholarlyArticle.create(headline = "My Paper", identifiers = ResizeArray [], authors = ResizeArray [author1;author2]) + let scaffold_Publication = ScholarlyArticleConversion.decomposeScholarlyArticle scholarlyArticle + let p = ScholarlyArticleConversion.composeScholarlyArticle scaffold_Publication + Expect.equal p scholarlyArticle "Publication should match" + ) + ] + +let tests_GetDataFilesFromProcesses = + testList "GetDataFilesFromProcesses" [ + testCase "EmptyArray" (fun () -> + let processes = ResizeArray [] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.isEmpty dataFiles "Should have no data files" + ) + testCase "SingleProcessNoDataFiles" (fun () -> + let p = LabProcess.create(name = Identifier.createMissingIdentifier()) + let processes = ResizeArray [p] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.isEmpty dataFiles "Should have no data files" + ) + testCase "InputAndOutputFile" (fun () -> + let p = LabProcess.create(name = Identifier.createMissingIdentifier()) + let input = File.create(name = "InputFile") + let output = File.create(name = "OutputFile") + LabProcess.setObjects(p, ResizeArray [input]) + LabProcess.setResults(p, ResizeArray [output]) + let processes = ResizeArray [p] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.hasLength dataFiles 2 "Should have 2 data files" + Expect.equal dataFiles.[0] input "First data file should be input" + Expect.equal dataFiles.[1] output "Second data file should be output" + ) + testCase "FragmentCorrectFieldCopies" (fun () -> + let p = LabProcess.create(name = Identifier.createMissingIdentifier()) + let encodingFormat = "text/csv" + let comment = ROCrate.Comment.create(name = "MyCommentKey", text = "MyCommentValue") + let input = File.create(name = "InputFile#Fragment1", encodingFormat = encodingFormat, comments = ResizeArray [comment]) + LabProcess.setObjects(p, ResizeArray [input]) + let processes = ResizeArray [p] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.hasLength dataFiles 1 "Should have 1 data file" + let first = dataFiles.[0] + Expect.equal (File.getNameAsString first) "InputFile" "First data file should be input" + let encodFormat' = Expect.wantSome (File.tryGetEncodingFormatAsString first) "Encoding format was not copied" + Expect.equal encodFormat' encodingFormat "Encoding format should be copied" + let comments = File.getComments first + Expect.hasLength comments 1 "Should have 1 comment" + Expect.equal comments.[0] comment "Comment should be copied" + let fragments = Dataset.getHasPartsAsFile first + Expect.hasLength fragments 1 "Should have 1 fragment" + Expect.equal fragments.[0] input "Fragment should be input" + ) + testCase "FragmentsOfDifferentFiles" (fun () -> + let p = LabProcess.create(name = Identifier.createMissingIdentifier()) + let input1 = File.create(name = "InputFile1#Fragment1") + let output2 = File.create(name = "InputFile2#Fragment2") + LabProcess.setObjects(p, ResizeArray [input1]) + LabProcess.setResults(p, ResizeArray [output2]) + let processes = ResizeArray [p] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.hasLength dataFiles 2 "Should have 2 data files" + let first = dataFiles.[0] + Expect.equal (File.getNameAsString first) "InputFile1" "First data file should be input1" + let second = dataFiles.[1] + Expect.equal (File.getNameAsString second) "InputFile2" "Second data file should be input2" + let firstFragments = Dataset.getHasPartsAsFile(first) + Expect.hasLength firstFragments 1 "First data file should have 1 fragment" + Expect.equal firstFragments.[0] input1 "First fragment should be Fragment1" + let secondFragments = Dataset.getHasPartsAsFile(second) + Expect.hasLength secondFragments 1 "Second data file should have 1 fragment" + Expect.equal secondFragments.[0] output2 "Second fragment should be Fragment2" + ) + testCase "FragmentsOfSameFile" (fun () -> + let p = LabProcess.create(name = Identifier.createMissingIdentifier()) + let input1 = File.create(name = "InputFile#Fragment1") + let output2 = File.create(name = "InputFile#Fragment2") + LabProcess.setObjects(p, ResizeArray [input1]) + LabProcess.setResults(p, ResizeArray [output2]) + let processes = ResizeArray [p] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.hasLength dataFiles 1 "Should have 1 data file" + let first = dataFiles.[0] + Expect.equal (File.getNameAsString first) "InputFile" "First data file should be input1" + let firstFragments = Dataset.getHasPartsAsFile first + Expect.hasLength firstFragments 2 "First data file should have 2 fragments" + Expect.equal firstFragments.[0] input1 "First fragment should be Fragment1" + Expect.equal firstFragments.[1] output2 "Second fragment should be Fragment2" + ) + testCase "ComplexMix" (fun () -> + let p1 = LabProcess.create(name = Identifier.createMissingIdentifier()) + let p1_input = File.create(name = "InputFile") + let p1_output1 = File.create(name = "MiddleFile#Fragment1") + let p1_output2 = File.create(name = "MiddleFile#Fragment2") + LabProcess.setObjects(p1, ResizeArray [p1_input]) + LabProcess.setResults(p1, ResizeArray [p1_output1;p1_output2]) + let p2_output1 = File.create(name = "OutFile1#Fragment1") + let p2_output2 = File.create(name = "OutFile2#Fragment2") + let p2 = LabProcess.create(name = Identifier.createMissingIdentifier()) + LabProcess.setObjects(p2, ResizeArray [p1_output1;p1_output2]) + LabProcess.setResults(p2, ResizeArray [p2_output1;p2_output2]) + let processes = ResizeArray [p1;p2] + let dataFiles = AssayConversion.getDataFilesFromProcesses processes + Expect.hasLength dataFiles 4 "Should have 4 data files" + Expect.equal dataFiles.[0] p1_input "First data file should be input" + let middleFile = dataFiles.[1] + Expect.equal (File.getNameAsString middleFile) "MiddleFile" "Second data file should be middle file" + let middleFragments = Dataset.getHasPartsAsFile middleFile + Expect.hasLength middleFragments 2 "Middle file should have 2 fragments" + Expect.equal middleFragments.[0] p1_output1 "First fragment should be Fragment1" + Expect.equal middleFragments.[1] p1_output2 "Second fragment should be Fragment2" + let out1 = dataFiles.[2] + Expect.equal (File.getNameAsString out1) "OutFile1" "Third data file should be output1" + let out1_Fragments = Dataset.getHasPartsAsFile out1 + Expect.hasLength out1_Fragments 1 "Output1 should have 1 fragment" + Expect.equal out1_Fragments.[0] p2_output1 "First fragment should be Fragment1" + let out2 = dataFiles.[3] + Expect.equal (File.getNameAsString out2) "OutFile2" "Fourth data file should be output2" + let out2_Fragments = Dataset.getHasPartsAsFile out2 + Expect.hasLength out2_Fragments 1 "Output2 should have 1 fragment" + Expect.equal out2_Fragments.[0] p2_output2 "First fragment should be Fragment2" + ) + ] + +let tests_Assay = + testList "Assay" [ + testCase "Empty_FromScaffold" (fun () -> + let p = ArcAssay.init("My Assay") + let ro_Assay = AssayConversion.composeAssay p + let p' = AssayConversion.decomposeAssay ro_Assay + Expect.equal p' p "Assay should match" + ) + testCase "Full_FromScaffold" (fun () -> + let measurementType = OntologyAnnotation(name = "sugar measurement", tsr = "DPBO", tan = "DPBO:0000120") + let technologyType = OntologyAnnotation(name = "Photometry", tsr = "NCIT", tan = "NCIT:C65109") + let technologyPlatform = OntologyAnnotation(name = "Infinite M200 plate reader (Tecan)", tsr = "DPBO", tan = "DPBO:0000116") + let person = + let role = OntologyAnnotation(name = "Resarcher", tsr = "oo", tan = "oo:123") + ARCtrl.Person(orcid = "0000-0002-1825-0097", firstName = "John", lastName = "Doe", midInitials = "BD", email = "jd@email.com", phone = "123", fax = "456", address = "123 Main St", affiliation = "My University",roles = ResizeArray [role]) + let table2 = ArcTable.init("Table2") + table2.Headers <- Helper.twoRowsDifferentParamValue.Headers + table2.Values <- Helper.twoRowsDifferentParamValue.Values + let p = + ArcAssay( + identifier = "My Assay", + measurementType = measurementType, + technologyType = technologyType, + technologyPlatform = technologyPlatform, + performers = ResizeArray [person], + tables = ResizeArray [Helper.singleRowMixedValues; table2] + ) + let ro_Assay = AssayConversion.composeAssay p + let p' = AssayConversion.decomposeAssay ro_Assay + Expect.equal p' p "Assay should match" + ) + ] + + +let tests_Investigation = + testList "Investigation" [ + testCase "Empty_FromScaffold" (fun () -> + let p = ArcInvestigation( + identifier = "My Investigation", + title = "My Best Investigation" + ) + let ro_Investigation = InvestigationConversion.composeInvestigation p + let p' = InvestigationConversion.decomposeInvestigation ro_Investigation + Expect.isSome p'.PublicReleaseDate "PublicReleaseDate default value should be set" + p'.PublicReleaseDate <- None // As a default value is used otherwise + Expect.equal p' p "Investigation should match" + ) + testCase "TopLevel_FromScaffold" (fun () -> + let publication = + let authors = "Lukas Weil, John Doe" + let comment = Comment("MyCommentKey","MyCommentValue") + let commentOnlyKey = Comment("MyEmptyKey") + let status = OntologyAnnotation(name = "Published", tsr = "oo", tan = "oo:123") + ARCtrl.Publication.create(title = "My Paper", doi = "10.1234/5678", authors = authors, status = status, comments = ResizeArray [comment; commentOnlyKey]) + let person = + let role = OntologyAnnotation(name = "Resarcher", tsr = "oo", tan = "oo:123") + ARCtrl.Person(orcid = "0000-0002-1825-0097", firstName = "John", lastName = "Doe", midInitials = "BD", email = "jd@email.com", phone = "123", fax = "456", address = "123 Main St", affiliation = "My University",roles = ResizeArray [role]) + let comment = Comment("MyCommentKey","MyCommentValue") + let p = ArcInvestigation( + identifier = "My Investigation", + title = "My Best Investigation", + description = "My Description is very good and such", + publicReleaseDate = DateTime.toString System.DateTime.Now, + submissionDate = DateTime.toString System.DateTime.Now, + publications = ResizeArray [publication], + contacts = ResizeArray [person], + comments = ResizeArray [comment] + ) + let ro_Investigation = InvestigationConversion.composeInvestigation p + let p' = InvestigationConversion.decomposeInvestigation ro_Investigation + Expect.equal p' p "Investigation should match" + ) + testCase "TopLevel_FromScaffold_Flattened" (fun () -> + let publication = + let authors = "Lukas Weil, John Doe" + let comment = Comment("MyCommentKey","MyCommentValue") + let commentOnlyKey = Comment("MyEmptyKey") + let status = OntologyAnnotation(name = "Published", tsr = "oo", tan = "oo:456") + ARCtrl.Publication.create(title = "My Paper", doi = "10.1234/5678", authors = authors, status = status, comments = ResizeArray [comment; commentOnlyKey]) + let person = + let role = OntologyAnnotation(name = "Resarcher", tsr = "oo", tan = "oo:123") + ARCtrl.Person(orcid = "0000-0002-1825-0097", firstName = "John", lastName = "Doe", midInitials = "BD", email = "jd@email.com", phone = "123", fax = "456", address = "123 Main St", affiliation = "My University",roles = ResizeArray [role]) + let comment = Comment("MyCommentKey2","MyCommentValue2") + let p = ArcInvestigation( + identifier = "My Investigation", + title = "My Best Investigation", + description = "My Description is very good and such", + publicReleaseDate = DateTime.toString System.DateTime.Now, + submissionDate = DateTime.toString System.DateTime.Now, + publications = ResizeArray [publication], + contacts = ResizeArray [person], + comments = ResizeArray [comment] + ) + let ro_Investigation = InvestigationConversion.composeInvestigation p + let graph = ro_Investigation.Flatten() + // Test that flatten worked + Expect.isTrue (graph.Nodes.Count > 0) "Graph should have properties" + let personRef = Expect.wantSome (ro_Investigation.TryGetPropertyAsSingleton(Dataset.creator)) "Investigation should still have creator" + Expect.isTrue (personRef :? LDRef) "Investigation should be flattened correctly" + // + let p' = InvestigationConversion.decomposeInvestigation(ro_Investigation, graph = graph) + Expect.equal p' p "Investigation should match" + ) + testCase "AssayAndStudy_FromScaffold" (fun () -> + let assay = ArcAssay.init("My Assay") + let study = ArcStudy.init("My Study") + let p = ArcInvestigation( + identifier = "My Investigation", + title = "My Best Investigation", + assays = ResizeArray [assay], + studies = ResizeArray [study] + ) + let ro_Investigation = InvestigationConversion.composeInvestigation p + let p' = InvestigationConversion.decomposeInvestigation ro_Investigation + Expect.isSome p'.PublicReleaseDate "PublicReleaseDate default value should be set" + p'.PublicReleaseDate <- None // As a default value is used otherwise + Expect.equal p' p "Investigation should match" + ) + ] + + + +let main = + testList "ArcROCrateConversion" [ + tests_DefinedTerm + tests_PropertyValue + tests_ProcessInput + tests_ProcessOutput + //tests_ProtocolTransformation + tests_ArcTableProcess + tests_ArcTablesProcessSeq + tests_Person + tests_Publication + tests_GetDataFilesFromProcesses + tests_Assay + tests_Investigation + ] \ No newline at end of file diff --git a/tests/Core/ArcJsonConversion.Tests.fs b/tests/Core/ArcJsonConversion.Tests.fs index a57f8fc8..49f5a1d6 100644 --- a/tests/Core/ArcJsonConversion.Tests.fs +++ b/tests/Core/ArcJsonConversion.Tests.fs @@ -1,8 +1,8 @@ -module ArcJsonConversion.Tests +module ArcJsonConversion.Tests open ARCtrl open ARCtrl.Process -open Conversion +open ARCtrl.Process.Conversion open TestingUtils module Helper = diff --git a/tests/Json/ARCtrl.Json.Tests.fsproj b/tests/Json/ARCtrl.Json.Tests.fsproj index fa5116c4..7fc9da1d 100644 --- a/tests/Json/ARCtrl.Json.Tests.fsproj +++ b/tests/Json/ARCtrl.Json.Tests.fsproj @@ -33,7 +33,9 @@ - + + + diff --git a/tests/Json/LDObject.Tests.fs b/tests/Json/LDObject.Tests.fs deleted file mode 100644 index ad053dc7..00000000 --- a/tests/Json/LDObject.Tests.fs +++ /dev/null @@ -1,122 +0,0 @@ -module Tests.LDObject - -open TestingUtils -open TestObjects.Json.ROCrate -open ARCtrl -open ARCtrl.ROCrate -open ARCtrl.Json -open DynamicObj - -let private test_read = testList "Read" [ - testCase "onlyIDAndType" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.onlyIDAndType) - Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - testCase "onlyID" <| fun _ -> - let f = fun _ -> LDObject.fromROCrateJsonString(GenericObjects.onlyID) |> ignore - Expect.throws f "Should fail if Type is missing" - testCase "onlyType" <| fun _ -> - let f = fun _ -> LDObject.fromROCrateJsonString(GenericObjects.onlyType) |> ignore - Expect.throws f "Should fail if ID is missing" - testCase "withStringFields" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withStringFields) - Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let name = Expect.wantSome (DynObj.tryGetTypedPropertyValue "name" json) "field name was not parsed" - Expect.equal name "MyName" "field name was not parsed correctly" - let description = Expect.wantSome (DynObj.tryGetTypedPropertyValue "description" json) "field description was not parsed" - Expect.equal description "MyDescription" "field description was not parsed correctly" - testCase "withIntFields" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withIntFields) - Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let number = Expect.wantSome (DynObj.tryGetTypedPropertyValue "number" json) "field number was not parsed" - Expect.equal number 42 "field number was not parsed correctly" - let anotherNumber = Expect.wantSome (DynObj.tryGetTypedPropertyValue "anotherNumber" json) "field anotherNumber was not parsed" - Expect.equal anotherNumber 1337 "field anotherNumber was not parsed correctly" - testCase "withStringArray" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withStringArray) - Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let names = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "names" json) "field names was not parsed" - Expect.equal names.Count 2 "ResizeArray length is wrong" - Expect.equal names.[0] "MyName" "First name was not parsed correctly" - Expect.equal names.[1] "MySecondName" "Second name was not parsed correctly" - testCase "withNestedObject" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withNestedObject) - Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue "nested" json) "field nested was not parsed" - Expect.equal nested.Id "MyIdentifier" "nested id was not parsed correctly" - Expect.equal nested.SchemaType "MyType" "nested type was not parsed correctly" - testCase "withObjectArray" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withObjectArray) - Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "nested" json) "field nested was not parsed" - Expect.equal nested.Count 2 "ResizeArray length is wrong" - let o1 = nested.[0] :?> LDObject - Expect.equal o1.Id "MyIdentifier" "First nested id was not parsed correctly" - Expect.equal o1.SchemaType "MyType" "First nested type was not parsed correctly" - let o2 = nested.[1] :?> LDObject - Expect.equal o2.Id "MyIdentifier" "Second nested id was not parsed correctly" - Expect.equal o2.SchemaType "MyType" "Second nested type was not parsed correctly" - testCase "withMixedArray" <| fun _ -> - let json = LDObject.fromROCrateJsonString(GenericObjects.withMixedArray) - Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" - Expect.equal json.SchemaType "MyType" "type was not parsed correctly" - let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "nested" json) "field nested was not parsed" - Expect.equal nested.Count 3 "ResizeArray length is wrong" - let o1 = nested.[0] :?> LDObject - Expect.equal o1.Id "MyIdentifier" "First nested id of object was not parsed correctly" - Expect.equal o1.SchemaType "MyType" "First nested type of object was not parsed correctly" - let o2 = nested.[1] :?> string - Expect.equal o2 "Value2" "Second nested string was not parsed correctly" - let o3 = nested.[2] :?> int - Expect.equal o3 42 "Third nested int was not parsed correctly" -] - -let test_write = testList "write" [ - testCase "onlyIDAndType" <| fun _ -> - let json = GenericObjects.onlyIDAndType - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withStringFields" <| fun _ -> - let json = GenericObjects.withStringFields - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withIntFields" <| fun _ -> - let json = GenericObjects.withIntFields - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withStringArray" <| fun _ -> - let json = GenericObjects.withStringArray - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withNestedObject" <| fun _ -> - let json = GenericObjects.withNestedObject - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withObjectArray" <| fun _ -> - let json = GenericObjects.withObjectArray - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - testCase "withMixedArray" <| fun _ -> - let json = GenericObjects.withMixedArray - let object = LDObject.fromROCrateJsonString(json) - let output = LDObject.toROCrateJsonString() object - Expect.stringEqual output json "Output string is not correct" - - -] - -let main = testList "LDObject" [ - test_read - test_write -] \ No newline at end of file diff --git a/tests/Json/Main.fs b/tests/Json/Main.fs index ffec170f..cf49be09 100644 --- a/tests/Json/Main.fs +++ b/tests/Json/Main.fs @@ -21,7 +21,9 @@ let all = testSequenced <| testList "Json" [ Tests.Process.ProcessInput.main Tests.Process.Protocol.main Tests.Process.Process.main - Tests.LDObject.main + Tests.LDContext.main + Tests.LDNode.main + Tests.LDGraph.main Tests.SchemaValidation.main ] diff --git a/tests/Json/ROCrate/LDContext.Tests.fs b/tests/Json/ROCrate/LDContext.Tests.fs new file mode 100644 index 00000000..b8f9ef88 --- /dev/null +++ b/tests/Json/ROCrate/LDContext.Tests.fs @@ -0,0 +1,28 @@ +module Tests.LDContext + +open TestingUtils +open TestObjects.Json.ROCrate +open ARCtrl +open ARCtrl.ROCrate +open ARCtrl.Json +open DynamicObj + +let private test_read = testList "Read" [ + testCase "DefinedTerm" <| fun _ -> + let context = Decode.fromJsonString LDContext.decoder context_DefinedTerm + let resolvedName = Expect.wantSome (context.TryResolveTerm("annotationValue")) "Could not resolve term" + Expect.equal resolvedName "http://schema.org/name" "term was not resolved correctly" + Expect.hasLength context.Mappings 6 "context was not read correctly" + ] + +let private test_write = testList "Write" [ + testCase "onlyIDAndType" <| fun _ -> + let context = Decode.fromJsonString LDContext.decoder context_DefinedTerm + let json = LDContext.encoder context |> Encode.toJsonString 0 + Expect.stringEqual json context_DefinedTerm "context was not written correctly" + ] + +let main = testList "LDContext" [ + test_read + test_write +] \ No newline at end of file diff --git a/tests/Json/ROCrate/LDGraph.Tests.fs b/tests/Json/ROCrate/LDGraph.Tests.fs new file mode 100644 index 00000000..e09582a4 --- /dev/null +++ b/tests/Json/ROCrate/LDGraph.Tests.fs @@ -0,0 +1,35 @@ +module Tests.LDGraph + +open TestingUtils +open TestObjects.Json.ROCrate +open ARCtrl +open ARCtrl.ROCrate +open ARCtrl.Json +open DynamicObj + +let private test_read = testList "Read" [ + testCase "Minimal_ROCrate" <| fun _ -> + let graph = LDGraph.fromROCrateJsonString roCrate_minimal + // Expect.sequenceEqual graph.Properties.Keys ["@context"] "only context property should exist" + Expect.isSome (graph.TryGetContext()) "context should exist" + Expect.isEmpty (graph.GetDynamicPropertyNames()) "only context property should exist" + Expect.hasLength graph.Nodes 2 "should have 2 nodes" + let firstExpectedObject = LDNode("ro-crate-metadata.json", ResizeArray ["CreativeWork"]) + firstExpectedObject.SetProperty("about", LDRef("./")) + firstExpectedObject.SetProperty("conformsTo", LDRef("https://w3id.org/ro/crate/1.2-DRAFT")) + let secondExpectedObject = LDNode("./", ResizeArray ["Dataset"]) + Expect.equal graph.Nodes.[0] firstExpectedObject "first node should be the metadata" + Expect.equal graph.Nodes.[1] secondExpectedObject "second node should be the dataset" +] + +let private test_write = testList "Write" [ + testCase "Minimal_ROCrate" <| fun _ -> + let graph = LDGraph.fromROCrateJsonString roCrate_minimal + let json = graph.ToROCrateJsonString() + Expect.stringEqual json roCrate_minimal "should be equal" +] + +let main = testList "LDGraph" [ + test_read + test_write +] \ No newline at end of file diff --git a/tests/Json/ROCrate/LDNode.Tests.fs b/tests/Json/ROCrate/LDNode.Tests.fs new file mode 100644 index 00000000..93f9dbae --- /dev/null +++ b/tests/Json/ROCrate/LDNode.Tests.fs @@ -0,0 +1,233 @@ +module Tests.LDNode + +open TestingUtils +open TestObjects.Json.ROCrate +open ARCtrl +open ARCtrl.ROCrate +open ARCtrl.Json +open DynamicObj + +let private test_read = testList "Read" [ + testCase "onlyIDAndType" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.onlyIDAndType) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + testCase "onlyID" <| fun _ -> + let f = fun _ -> LDNode.fromROCrateJsonString(GenericObjects.onlyID) |> ignore + Expect.throws f "Should fail if Type is missing" + testCase "onlyType" <| fun _ -> + let f = fun _ -> LDNode.fromROCrateJsonString(GenericObjects.onlyType) |> ignore + Expect.throws f "Should fail if ID is missing" + testCase "twoTypesAndID" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.twoTypesAndID) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"; "MySecondType"] "type was not parsed correctly" + testCase "withStringFields" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withStringFields) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let name = Expect.wantSome (DynObj.tryGetTypedPropertyValue "name" json) "field name was not parsed" + Expect.equal name "MyName" "field name was not parsed correctly" + let description = Expect.wantSome (DynObj.tryGetTypedPropertyValue "description" json) "field description was not parsed" + Expect.equal description "MyDescription" "field description was not parsed correctly" + testCase "withIntFields" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withIntFields) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let number = Expect.wantSome (DynObj.tryGetTypedPropertyValue "number" json) "field number was not parsed" + Expect.equal number 42 "field number was not parsed correctly" + let anotherNumber = Expect.wantSome (DynObj.tryGetTypedPropertyValue "anotherNumber" json) "field anotherNumber was not parsed" + Expect.equal anotherNumber 1337 "field anotherNumber was not parsed correctly" + testCase "withStringArray" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withStringArray) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let names = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "names" json) "field names was not parsed" + Expect.equal names.Count 2 "ResizeArray length is wrong" + Expect.equal names.[0] "MyName" "First name was not parsed correctly" + Expect.equal names.[1] "MySecondName" "Second name was not parsed correctly" + testCase "withExpandedStringFieldNoType" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withExpandedStringFieldNoType) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let name = Expect.wantSome (json.TryGetProperty "name") "field name was not parsed" + let expected = LDValue("MyName") + Expect.equal name expected "field name was not parsed correctly" + testCase "withExpandedStringFieldWithType" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withExpandedStringFieldWithType) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let name = Expect.wantSome (json.TryGetProperty "name") "field name was not parsed" + let expected = LDValue("MyName", valueType = "http://www.w3.org/2001/XMLSchema#string") + Expect.equal name expected "field name was not parsed correctly" + testCase "withExpandedIntFieldWithType" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withExpandedIntFieldWithType) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let number = Expect.wantSome (json.TryGetProperty "number") "field number was not parsed" + let expected = LDValue(42, valueType = "http://www.w3.org/2001/XMLSchema#int") + Expect.equal number expected "field number was not parsed correctly" + testCase "withLDRefObject" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withLDRefObject) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let ref = Expect.wantSome (json.TryGetProperty "nested") "field ref was not parsed" + let expected = LDRef("RefIdentifier") + Expect.equal ref expected "ref id was not parsed correctly" + testCase "withNestedObject" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withNestedObject) + Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue "nested" json) "field nested was not parsed" + Expect.equal nested.Id "MyIdentifier" "nested id was not parsed correctly" + Expect.sequenceEqual nested.SchemaType ResizeArray["MyType"] "nested type was not parsed correctly" + testCase "withObjectArray" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withObjectArray) + Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "nested" json) "field nested was not parsed" + Expect.equal nested.Count 2 "ResizeArray length is wrong" + let o1 = nested.[0] :?> LDNode + Expect.equal o1.Id "MyIdentifier" "First nested id was not parsed correctly" + Expect.sequenceEqual o1.SchemaType ResizeArray["MyType"] "First nested type was not parsed correctly" + let o2 = nested.[1] :?> LDNode + Expect.equal o2.Id "MyIdentifier" "Second nested id was not parsed correctly" + Expect.sequenceEqual o2.SchemaType ResizeArray["MyType"] "Second nested type was not parsed correctly" + testCase "withMixedArray" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withMixedArray) + Expect.equal json.Id "OuterIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + let nested = Expect.wantSome (DynObj.tryGetTypedPropertyValue> "nested" json) "field nested was not parsed" + Expect.equal nested.Count 3 "ResizeArray length is wrong" + let o1 = nested.[0] :?> LDNode + Expect.equal o1.Id "MyIdentifier" "First nested id of object was not parsed correctly" + Expect.sequenceEqual o1.SchemaType ResizeArray["MyType"] "First nested type of object was not parsed correctly" + let o2 = nested.[1] :?> string + Expect.equal o2 "Value2" "Second nested string was not parsed correctly" + let o3 = nested.[2] :?> int + Expect.equal o3 42 "Third nested int was not parsed correctly" + testCase "withAdditionalTypeString" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withAdditionalTypeString) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + Expect.sequenceEqual json.AdditionalType ResizeArray["additionalType"] "additionalType was not parsed correctly" + testCase "withAdditionalTypeArray" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withAdditionalTypeArray) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + Expect.sequenceEqual json.AdditionalType ResizeArray["additionalType"] "additionalType was not parsed correctly" + testCase "withAddtionalTypeArrayMultipleEntries" <| fun _ -> + let json = LDNode.fromROCrateJsonString(GenericObjects.withAddtionalTypeArrayMultipleEntries) + Expect.equal json.Id "MyIdentifier" "id was not parsed correctly" + Expect.sequenceEqual json.SchemaType ResizeArray["MyType"] "type was not parsed correctly" + Expect.sequenceEqual json.AdditionalType ResizeArray["additionalType1"; "additionalType2"] "additionalType was not parsed correctly" +] + +let test_write = testList "write" [ + // The tests suffixed with 'NoTypeArray' are not real roundtrips, as we parse string OR array fields but always write arrays for the @type field. + testCase "onlyIDAndType" <| fun _ -> + let json = GenericObjects.onlyIDAndType + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "onlyIDAndTypeNoTypeArray" <| fun _ -> + let json = GenericObjects.onlyIDAndTypeNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.onlyIDAndType "Output string is not correct" + + testCase "twoTypesAndID" <| fun _ -> + let json = GenericObjects.twoTypesAndID + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + + testCase "withStringFields" <| fun _ -> + let json = GenericObjects.withStringFields + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withStringFieldsNoTypeArray" <| fun _ -> + let json = GenericObjects.withStringFieldsNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withStringFields "Output string is not correct" + + testCase "withIntFields" <| fun _ -> + let json = GenericObjects.withIntFields + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withIntFieldsNoTypeArray" <| fun _ -> + let json = GenericObjects.withIntFieldsNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withIntFields "Output string is not correct" + + testCase "withStringArray" <| fun _ -> + let json = GenericObjects.withStringArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withStringArrayNoTypeArray" <| fun _ -> + let json = GenericObjects.withStringArrayNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withStringArray "Output string is not correct" + + testCase "withNestedObject" <| fun _ -> + let json = GenericObjects.withNestedObject + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withNestedObjectNoTypeArray" <| fun _ -> + let json = GenericObjects.withNestedObjectNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withNestedObject "Output string is not correct" + + testCase "withObjectArray" <| fun _ -> + let json = GenericObjects.withObjectArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withObjectArrayNoTypeArray" <| fun _ -> + let json = GenericObjects.withObjectArrayNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withObjectArray "Output string is not correct" + + testCase "withMixedArray" <| fun _ -> + let json = GenericObjects.withMixedArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + testCase "withMixedArrayNoTypeArray" <| fun _ -> + let json = GenericObjects.withMixedArrayNoTypeArray + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output GenericObjects.withMixedArray "Output string is not correct" + + testCase "withAddtionalTypeArray" <| fun _ -> + let json = GenericObjects.withAdditionalTypeArray + let jsonOut = GenericObjects.withAdditionalTypeString + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output jsonOut "Output string is not correct" + testCase "withAddtionalTypeArrayMultipleEntries" <| fun _ -> + let json = GenericObjects.withAddtionalTypeArrayMultipleEntries + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" + + testCase "withAddtionalTypeString" <| fun _ -> + let json = GenericObjects.withAdditionalTypeString + let object = LDNode.fromROCrateJsonString(json) + let output = LDNode.toROCrateJsonString() object + Expect.stringEqual output json "Output string is not correct" +] + +let main = testList "LDNode" [ + test_read + test_write +] \ No newline at end of file diff --git a/tests/ROCrate/ARCtrl.ROCrate.Tests.fsproj b/tests/ROCrate/ARCtrl.ROCrate.Tests.fsproj index 4d439667..40a597b0 100644 --- a/tests/ROCrate/ARCtrl.ROCrate.Tests.fsproj +++ b/tests/ROCrate/ARCtrl.ROCrate.Tests.fsproj @@ -7,8 +7,9 @@ - - + + + diff --git a/tests/ROCrate/Common.fs b/tests/ROCrate/Common.fs index 0c56cc5f..45c77801 100644 --- a/tests/ROCrate/Common.fs +++ b/tests/ROCrate/Common.fs @@ -7,32 +7,49 @@ open TestingUtils module Expect = - let inline LDObjectHasId (expectedId:string) (roc:#LDObject) = + let inline LDNodeHasId (expectedId:string) (roc:#LDNode) = Expect.equal roc.Id expectedId "object did not contain correct @id" - let inline LDObjectHasType (expectedType:string) (roc:#LDObject) = - Expect.equal roc.SchemaType expectedType "object did not contain correct @type" - - let inline LDObjectHasAdditionalType (expectedAdditionalType:string) (roc:#LDObject) = - Expect.isSome roc.AdditionalType "additionalType was None" - Expect.equal roc.AdditionalType (Some expectedAdditionalType) "object did not contain correct additionalType" - - let inline LDObjectHasDynamicProperty (expectedPropertyName:string) (expectedPropertyValue:'P) (roc:#LDObject) = + let inline LDNodeHasType (expectedType:string) (roc:#LDNode) = + Expect.containsAll + roc.SchemaType + [expectedType] + "object did not contain correct @type" + + let inline LDNodeHasTypes (expectedTypes:seq) (roc:#LDNode) = + Expect.containsAll + roc.SchemaType + expectedTypes + "object did not contain correct @types" + + let inline LDNodeHasAdditionalType (expectedAdditionalType:string) (roc:#LDNode) = + Expect.containsAll + roc.AdditionalType + [expectedAdditionalType] + "object did not contain correct additionalType" + + let inline LDNodeHasAdditionalTypes (expectedAdditionalTypes:seq) (roc:#LDNode) = + Expect.containsAll + roc.AdditionalType + expectedAdditionalTypes + "object did not contain correct additionalTypes" + + let inline LDNodeHasDynamicProperty (expectedPropertyName:string) (expectedPropertyValue:'P) (roc:#LDNode) = Expect.isSome (roc.TryGetDynamicPropertyHelper(expectedPropertyName)) $"object did not contain the dynamic property '{expectedPropertyName}'" Expect.equal (DynObj.tryGetTypedPropertyValue<'P> expectedPropertyName roc) (Some expectedPropertyValue) $"property value of '{expectedPropertyName}' was not correct" - let inline LDObjectHasStaticProperty (expectedPropertyName:string) (expectedPropertyValue:'P) (roc:#LDObject) = - Expect.isSome (roc.TryGetDynamicPropertyHelper(expectedPropertyName)) $"object did not contain the dynamic property '{expectedPropertyName}'" + let inline LDNodeHasStaticProperty (expectedPropertyName:string) (expectedPropertyValue:'P) (roc:#LDNode) = + Expect.isSome (roc.TryGetStaticPropertyHelper(expectedPropertyName)) $"object did not contain the static property '{expectedPropertyName}'" Expect.equal (DynObj.tryGetTypedPropertyValue<'P> expectedPropertyName roc) (Some expectedPropertyValue) $"property value of '{expectedPropertyName}' was not correct" - let inline LDObjectHasExpectedInterfaceMembers (expectedType:string) (expectedId:string) (expectedAdditionalType:string option) (roc:#LDObject) = - let interfacerino = roc :> ILDObject - Expect.equal interfacerino.SchemaType expectedType "object did not contain correct @type via interface access" - Expect.equal interfacerino.Id expectedId "object did not contain correct @id via interface access" - Expect.equal interfacerino.AdditionalType expectedAdditionalType "object did not contain correct additionalType via interface access" + //let inline LDNodeHasExpectedInterfaceMembers (expectedTypes: seq) (expectedId:string) (expectedAdditionalTypes: seq) (roc:#LDNode) = + // let interfacerino = roc :> ILDNode + // Expect.sequenceEqual interfacerino.SchemaType expectedTypes "object did not contain correct @types via interface access" + // Expect.equal interfacerino.Id expectedId "object did not contain correct @id via interface access" + // Expect.sequenceEqual interfacerino.AdditionalType expectedAdditionalTypes "object did not contain correct additionalTypes via interface access" diff --git a/tests/ROCrate/ISAProfile/Assay.Tests.fs b/tests/ROCrate/ISAProfile/Assay.Tests.fs index 70eb7a86..37972aec 100644 --- a/tests/ROCrate/ISAProfile/Assay.Tests.fs +++ b/tests/ROCrate/ISAProfile/Assay.Tests.fs @@ -26,30 +26,30 @@ let all_properties = Assay( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "assay_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Assay" mandatory_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "assay_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Assay" mandatory_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "assay_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Assay" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties - testCase "about" <| fun _ -> Expect.LDObjectHasDynamicProperty "about" "about" all_properties - testCase "comment" <| fun _ -> Expect.LDObjectHasDynamicProperty "comment" "comment" all_properties - testCase "creator" <| fun _ -> Expect.LDObjectHasDynamicProperty "creator" "creator" all_properties - testCase "hasPart" <| fun _ -> Expect.LDObjectHasDynamicProperty "hasPart" "hasPart" all_properties - testCase "measurementMethod" <| fun _ -> Expect.LDObjectHasDynamicProperty "measurementMethod" "measurementMethod" all_properties - testCase "measurementTechnique" <| fun _ -> Expect.LDObjectHasDynamicProperty "measurementTechnique" "measurementTechnique" all_properties - testCase "url" <| fun _ -> Expect.LDObjectHasDynamicProperty "url" "url" all_properties - testCase "variableMeasured" <| fun _ -> Expect.LDObjectHasDynamicProperty "variableMeasured" "variableMeasured" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "assay_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Assay" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties + testCase "about" <| fun _ -> Expect.LDNodeHasDynamicProperty "about" "about" all_properties + testCase "comment" <| fun _ -> Expect.LDNodeHasDynamicProperty "comment" "comment" all_properties + testCase "creator" <| fun _ -> Expect.LDNodeHasDynamicProperty "creator" "creator" all_properties + testCase "hasPart" <| fun _ -> Expect.LDNodeHasDynamicProperty "hasPart" "hasPart" all_properties + testCase "measurementMethod" <| fun _ -> Expect.LDNodeHasDynamicProperty "measurementMethod" "measurementMethod" all_properties + testCase "measurementTechnique" <| fun _ -> Expect.LDNodeHasDynamicProperty "measurementTechnique" "measurementTechnique" all_properties + testCase "url" <| fun _ -> Expect.LDNodeHasDynamicProperty "url" "url" all_properties + testCase "variableMeasured" <| fun _ -> Expect.LDNodeHasDynamicProperty "variableMeasured" "variableMeasured" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "assay_mandatory_properties_id" (Some "Assay") mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "assay_all_properties_id" (Some "Assay") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "assay_mandatory_properties_id" [|"Assay"|] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "assay_all_properties_id" [|"Assay"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -57,7 +57,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -72,7 +72,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -108,13 +108,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Data.Tests.fs b/tests/ROCrate/ISAProfile/Data.Tests.fs index bbeb6716..6c820de7 100644 --- a/tests/ROCrate/ISAProfile/Data.Tests.fs +++ b/tests/ROCrate/ISAProfile/Data.Tests.fs @@ -14,7 +14,7 @@ let mandatory_properties = Data( let all_properties = Data( id = "data_all_properties_id", name = "name", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), comment = "comment", encodingFormat = "encodingFormat", disambiguatingDescription = "disambiguatingDescription" @@ -22,24 +22,24 @@ let all_properties = Data( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "data_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/MediaObject" mandatory_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "data_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/MediaObject" mandatory_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "data_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/MediaObject" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "comment" <| fun _ -> Expect.LDObjectHasDynamicProperty "comment" "comment" all_properties - testCase "encodingFormat" <| fun _ -> Expect.LDObjectHasDynamicProperty "encodingFormat" "encodingFormat" all_properties - testCase "disambiguatingDescription" <| fun _ -> Expect.LDObjectHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "data_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/MediaObject" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "comment" <| fun _ -> Expect.LDNodeHasDynamicProperty "comment" "comment" all_properties + testCase "encodingFormat" <| fun _ -> Expect.LDNodeHasDynamicProperty "encodingFormat" "encodingFormat" all_properties + testCase "disambiguatingDescription" <| fun _ -> Expect.LDNodeHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/MediaObject" "data_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/MediaObject" "data_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/MediaObject"|] "data_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/MediaObject"|] "data_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -47,7 +47,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -62,7 +62,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -79,13 +79,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Dataset.Tests.fs b/tests/ROCrate/ISAProfile/Dataset.Tests.fs index f4468679..3ff76eed 100644 --- a/tests/ROCrate/ISAProfile/Dataset.Tests.fs +++ b/tests/ROCrate/ISAProfile/Dataset.Tests.fs @@ -7,23 +7,23 @@ open TestingUtils open Common let mandatory_properties = Dataset("dataset_mandatory_properties_id") -let all_properties = Dataset("dataset_all_properties_id", additionalType = "additionalType") +let all_properties = Dataset("dataset_all_properties_id", additionalType = ResizeArray([|"additionalType"|])) let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "dataset_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "dataset_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "dataset_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "dataset_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "dataset_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "dataset_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "dataset_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "dataset_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -31,7 +31,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -46,7 +46,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -63,13 +63,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Investigation.Tests.fs b/tests/ROCrate/ISAProfile/Investigation.Tests.fs index 8e051460..adb570b8 100644 --- a/tests/ROCrate/ISAProfile/Investigation.Tests.fs +++ b/tests/ROCrate/ISAProfile/Investigation.Tests.fs @@ -29,33 +29,33 @@ let all_properties = Investigation( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "investigation_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Investigation" mandatory_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "investigation_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Investigation" mandatory_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "investigation_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Investigation" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties - testCase "citation" <| fun _ -> Expect.LDObjectHasDynamicProperty "citation" "citation" all_properties - testCase "comment" <| fun _ -> Expect.LDObjectHasDynamicProperty "comment" "comment" all_properties - testCase "creator" <| fun _ -> Expect.LDObjectHasDynamicProperty "creator" "creator" all_properties - testCase "dateCreated" <| fun _ -> Expect.LDObjectHasDynamicProperty "dateCreated" "dateCreated" all_properties - testCase "dateModified" <| fun _ -> Expect.LDObjectHasDynamicProperty "dateModified" "dateModified" all_properties - testCase "datePublished" <| fun _ -> Expect.LDObjectHasDynamicProperty "datePublished" "datePublished" all_properties - testCase "hasPart" <| fun _ -> Expect.LDObjectHasDynamicProperty "hasPart" "hasPart" all_properties - testCase "headline" <| fun _ -> Expect.LDObjectHasDynamicProperty "headline" "headline" all_properties - testCase "mentions" <| fun _ -> Expect.LDObjectHasDynamicProperty "mentions" "mentions" all_properties - testCase "url" <| fun _ -> Expect.LDObjectHasDynamicProperty "url" "url" all_properties - testCase "description" <| fun _ -> Expect.LDObjectHasDynamicProperty "description" "description" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "investigation_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Investigation" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties + testCase "citation" <| fun _ -> Expect.LDNodeHasDynamicProperty "citation" "citation" all_properties + testCase "comment" <| fun _ -> Expect.LDNodeHasDynamicProperty "comment" "comment" all_properties + testCase "creator" <| fun _ -> Expect.LDNodeHasDynamicProperty "creator" "creator" all_properties + testCase "dateCreated" <| fun _ -> Expect.LDNodeHasDynamicProperty "dateCreated" "dateCreated" all_properties + testCase "dateModified" <| fun _ -> Expect.LDNodeHasDynamicProperty "dateModified" "dateModified" all_properties + testCase "datePublished" <| fun _ -> Expect.LDNodeHasDynamicProperty "datePublished" "datePublished" all_properties + testCase "hasPart" <| fun _ -> Expect.LDNodeHasDynamicProperty "hasPart" "hasPart" all_properties + testCase "headline" <| fun _ -> Expect.LDNodeHasDynamicProperty "headline" "headline" all_properties + testCase "mentions" <| fun _ -> Expect.LDNodeHasDynamicProperty "mentions" "mentions" all_properties + testCase "url" <| fun _ -> Expect.LDNodeHasDynamicProperty "url" "url" all_properties + testCase "description" <| fun _ -> Expect.LDNodeHasDynamicProperty "description" "description" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "investigation_mandatory_properties_id" (Some "Investigation") mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "investigation_all_properties_id" (Some "Investigation") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "investigation_mandatory_properties_id" [|"Investigation"|] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "investigation_all_properties_id" [|"Investigation"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -63,7 +63,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -78,7 +78,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -114,13 +114,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/LabProcess.tests.fs b/tests/ROCrate/ISAProfile/LabProcess.tests.fs index 23971baf..62da8d39 100644 --- a/tests/ROCrate/ISAProfile/LabProcess.tests.fs +++ b/tests/ROCrate/ISAProfile/LabProcess.tests.fs @@ -20,7 +20,7 @@ let all_properties = LabProcess( agent = "agent", object = "object", result = "result", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), executesLabProtocol = "executesLabProtocol", parameterValue = "parameterValue", endTime = "endTime", @@ -29,32 +29,32 @@ let all_properties = LabProcess( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "labprocess_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/LabProcess" mandatory_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" mandatory_properties - testCase "agent" <| fun _ -> Expect.LDObjectHasDynamicProperty "agent" "agent" mandatory_properties - testCase "object" <| fun _ -> Expect.LDObjectHasDynamicProperty "object" "object" mandatory_properties - testCase "result" <| fun _ -> Expect.LDObjectHasDynamicProperty "result" "result" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "labprocess_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/LabProcess" mandatory_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" mandatory_properties + testCase "agent" <| fun _ -> Expect.LDNodeHasDynamicProperty "agent" "agent" mandatory_properties + testCase "object" <| fun _ -> Expect.LDNodeHasDynamicProperty "object" "object" mandatory_properties + testCase "result" <| fun _ -> Expect.LDNodeHasDynamicProperty "result" "result" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "labprocess_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/LabProcess" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "agent" <| fun _ -> Expect.LDObjectHasDynamicProperty "agent" "agent" all_properties - testCase "object" <| fun _ -> Expect.LDObjectHasDynamicProperty "object" "object" all_properties - testCase "result" <| fun _ -> Expect.LDObjectHasDynamicProperty "result" "result" all_properties - testCase "executesLabProtocol" <| fun _ -> Expect.LDObjectHasDynamicProperty "executesLabProtocol" "executesLabProtocol" all_properties - testCase "parameterValue" <| fun _ -> Expect.LDObjectHasDynamicProperty "parameterValue" "parameterValue" all_properties - testCase "endTime" <| fun _ -> Expect.LDObjectHasDynamicProperty "endTime" "endTime" all_properties - testCase "disambiguatingDescription" <| fun _ -> Expect.LDObjectHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "labprocess_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/LabProcess" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "agent" <| fun _ -> Expect.LDNodeHasDynamicProperty "agent" "agent" all_properties + testCase "object" <| fun _ -> Expect.LDNodeHasDynamicProperty "object" "object" all_properties + testCase "result" <| fun _ -> Expect.LDNodeHasDynamicProperty "result" "result" all_properties + testCase "executesLabProtocol" <| fun _ -> Expect.LDNodeHasDynamicProperty "executesLabProtocol" "executesLabProtocol" all_properties + testCase "parameterValue" <| fun _ -> Expect.LDNodeHasDynamicProperty "parameterValue" "parameterValue" all_properties + testCase "endTime" <| fun _ -> Expect.LDNodeHasDynamicProperty "endTime" "endTime" all_properties + testCase "disambiguatingDescription" <| fun _ -> Expect.LDNodeHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/LabProcess" "labprocess_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/LabProcess" "labprocess_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/LabProcess"|] "labprocess_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/LabProcess"|] "labprocess_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -62,7 +62,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -77,7 +77,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -94,13 +94,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/LabProtocol.Tests.fs b/tests/ROCrate/ISAProfile/LabProtocol.Tests.fs index 588036c0..d5937535 100644 --- a/tests/ROCrate/ISAProfile/LabProtocol.Tests.fs +++ b/tests/ROCrate/ISAProfile/LabProtocol.Tests.fs @@ -12,7 +12,7 @@ let mandatory_properties = LabProtocol( let all_properties = LabProtocol( id = "labprotocol_all_properties_id", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), name = "name", intendedUse = "intendedUse", description = "description", @@ -26,28 +26,28 @@ let all_properties = LabProtocol( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "labprotocol_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/LabProtocol" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "labprotocol_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/LabProtocol" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "labprotocol_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/LabProtocol" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "intendedUse" <| fun _ -> Expect.LDObjectHasDynamicProperty "intendedUse" "intendedUse" all_properties - testCase "description" <| fun _ -> Expect.LDObjectHasDynamicProperty "description" "description" all_properties - testCase "url" <| fun _ -> Expect.LDObjectHasDynamicProperty "url" "url" all_properties - testCase "comment" <| fun _ -> Expect.LDObjectHasDynamicProperty "comment" "comment" all_properties - testCase "version" <| fun _ -> Expect.LDObjectHasDynamicProperty "version" "version" all_properties - testCase "labEquipment" <| fun _ -> Expect.LDObjectHasDynamicProperty "labEquipment" "labEquipment" all_properties - testCase "reagent" <| fun _ -> Expect.LDObjectHasDynamicProperty "reagent" "reagent" all_properties - testCase "computationalTool" <| fun _ -> Expect.LDObjectHasDynamicProperty "computationalTool" "computationalTool" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "labprotocol_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/LabProtocol" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "intendedUse" <| fun _ -> Expect.LDNodeHasDynamicProperty "intendedUse" "intendedUse" all_properties + testCase "description" <| fun _ -> Expect.LDNodeHasDynamicProperty "description" "description" all_properties + testCase "url" <| fun _ -> Expect.LDNodeHasDynamicProperty "url" "url" all_properties + testCase "comment" <| fun _ -> Expect.LDNodeHasDynamicProperty "comment" "comment" all_properties + testCase "version" <| fun _ -> Expect.LDNodeHasDynamicProperty "version" "version" all_properties + testCase "labEquipment" <| fun _ -> Expect.LDNodeHasDynamicProperty "labEquipment" "labEquipment" all_properties + testCase "reagent" <| fun _ -> Expect.LDNodeHasDynamicProperty "reagent" "reagent" all_properties + testCase "computationalTool" <| fun _ -> Expect.LDNodeHasDynamicProperty "computationalTool" "computationalTool" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/LabProtocol" "labprotocol_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/LabProtocol" "labprotocol_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/LabProtocol"|] "labprotocol_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/LabProtocol"|] "labprotocol_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -55,7 +55,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -70,7 +70,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -87,13 +87,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Person.Tests.fs b/tests/ROCrate/ISAProfile/Person.Tests.fs index 107dfb28..6aff6cac 100644 --- a/tests/ROCrate/ISAProfile/Person.Tests.fs +++ b/tests/ROCrate/ISAProfile/Person.Tests.fs @@ -14,7 +14,7 @@ let mandatory_properties = Person( let all_properties = Person( id = "person_all_properties_id", givenName = "givenName", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), familyName = "familyName", email = "email", identifier = "identifier", @@ -29,31 +29,31 @@ let all_properties = Person( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "person_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Person" mandatory_properties - testCase "givenName" <| fun _ -> Expect.LDObjectHasDynamicProperty "givenName" "givenName" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "person_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Person" mandatory_properties + testCase "givenName" <| fun _ -> Expect.LDNodeHasDynamicProperty "givenName" "givenName" all_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "person_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Person" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "givenName" <| fun _ -> Expect.LDObjectHasDynamicProperty "givenName" "givenName" all_properties - testCase "familyName" <| fun _ -> Expect.LDObjectHasDynamicProperty "familyName" "familyName" all_properties - testCase "email" <| fun _ -> Expect.LDObjectHasDynamicProperty "email" "email" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties - testCase "affiliation" <| fun _ -> Expect.LDObjectHasDynamicProperty "affiliation" "affiliation" all_properties - testCase "jobTitle" <| fun _ -> Expect.LDObjectHasDynamicProperty "jobTitle" "jobTitle" all_properties - testCase "additionalName" <| fun _ -> Expect.LDObjectHasDynamicProperty "additionalName" "additionalName" all_properties - testCase "address" <| fun _ -> Expect.LDObjectHasDynamicProperty "address" "address" all_properties - testCase "telephone" <| fun _ -> Expect.LDObjectHasDynamicProperty "telephone" "telephone" all_properties - testCase "faxNumber" <| fun _ -> Expect.LDObjectHasDynamicProperty "faxNumber" "faxNumber" all_properties - testCase "disambiguatingDescription" <| fun _ -> Expect.LDObjectHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "person_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Person" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "givenName" <| fun _ -> Expect.LDNodeHasDynamicProperty "givenName" "givenName" all_properties + testCase "familyName" <| fun _ -> Expect.LDNodeHasDynamicProperty "familyName" "familyName" all_properties + testCase "email" <| fun _ -> Expect.LDNodeHasDynamicProperty "email" "email" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties + testCase "affiliation" <| fun _ -> Expect.LDNodeHasDynamicProperty "affiliation" "affiliation" all_properties + testCase "jobTitle" <| fun _ -> Expect.LDNodeHasDynamicProperty "jobTitle" "jobTitle" all_properties + testCase "additionalName" <| fun _ -> Expect.LDNodeHasDynamicProperty "additionalName" "additionalName" all_properties + testCase "address" <| fun _ -> Expect.LDNodeHasDynamicProperty "address" "address" all_properties + testCase "telephone" <| fun _ -> Expect.LDNodeHasDynamicProperty "telephone" "telephone" all_properties + testCase "faxNumber" <| fun _ -> Expect.LDNodeHasDynamicProperty "faxNumber" "faxNumber" all_properties + testCase "disambiguatingDescription" <| fun _ -> Expect.LDNodeHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Person" "person_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Person" "person_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Person"|] "person_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Person"|] "person_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -61,7 +61,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -76,7 +76,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -93,13 +93,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/PropertyValue.Tests.fs b/tests/ROCrate/ISAProfile/PropertyValue.Tests.fs index c44ec118..7b997cee 100644 --- a/tests/ROCrate/ISAProfile/PropertyValue.Tests.fs +++ b/tests/ROCrate/ISAProfile/PropertyValue.Tests.fs @@ -20,32 +20,32 @@ let all_properties = PropertyValue( unitCode = "unitCode", unitText = "unitText", valueReference = "valueReference", - additionalType = "additionalType" + additionalType = ResizeArray([|"additionalType"|]) ) let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "propertyvalue_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/PropertyValue" mandatory_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "value" <| fun _ -> Expect.LDObjectHasDynamicProperty "value" "value" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "propertyvalue_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/PropertyValue" mandatory_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "value" <| fun _ -> Expect.LDNodeHasDynamicProperty "value" "value" all_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "propertyvalue_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/PropertyValue" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "value" <| fun _ -> Expect.LDObjectHasDynamicProperty "value" "value" all_properties - testCase "propertyID" <| fun _ -> Expect.LDObjectHasDynamicProperty "propertyID" "propertyID" all_properties - testCase "unitCode" <| fun _ -> Expect.LDObjectHasDynamicProperty "unitCode" "unitCode" all_properties - testCase "unitText" <| fun _ -> Expect.LDObjectHasDynamicProperty "unitText" "unitText" all_properties - testCase "valueReference" <| fun _ -> Expect.LDObjectHasDynamicProperty "valueReference" "valueReference" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "propertyvalue_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/PropertyValue" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "value" <| fun _ -> Expect.LDNodeHasDynamicProperty "value" "value" all_properties + testCase "propertyID" <| fun _ -> Expect.LDNodeHasDynamicProperty "propertyID" "propertyID" all_properties + testCase "unitCode" <| fun _ -> Expect.LDNodeHasDynamicProperty "unitCode" "unitCode" all_properties + testCase "unitText" <| fun _ -> Expect.LDNodeHasDynamicProperty "unitText" "unitText" all_properties + testCase "valueReference" <| fun _ -> Expect.LDNodeHasDynamicProperty "valueReference" "valueReference" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/PropertyValue" "propertyvalue_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/PropertyValue" "propertyvalue_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/PropertyValue"|] "propertyvalue_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/PropertyValue"|] "propertyvalue_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -53,7 +53,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -68,7 +68,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -85,13 +85,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Sample.tests.fs b/tests/ROCrate/ISAProfile/Sample.tests.fs index 659cb47d..afd14a9e 100644 --- a/tests/ROCrate/ISAProfile/Sample.tests.fs +++ b/tests/ROCrate/ISAProfile/Sample.tests.fs @@ -14,30 +14,30 @@ let mandatory_properties = Sample( let all_properties = Sample( id = "sample_all_properties_id", name = "name", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), additionalProperty = "additionalProperty", derivesFrom = "derivesFrom" ) let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "sample_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/Sample" mandatory_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "sample_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/Sample" mandatory_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "sample_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "bioschemas.org/Sample" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "name" <| fun _ -> Expect.LDObjectHasDynamicProperty "name" "name" all_properties - testCase "additionalProperty" <| fun _ -> Expect.LDObjectHasDynamicProperty "additionalProperty" "additionalProperty" all_properties - testCase "derivesFrom" <| fun _ -> Expect.LDObjectHasDynamicProperty "derivesFrom" "derivesFrom" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "sample_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "bioschemas.org/Sample" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "name" <| fun _ -> Expect.LDNodeHasDynamicProperty "name" "name" all_properties + testCase "additionalProperty" <| fun _ -> Expect.LDNodeHasDynamicProperty "additionalProperty" "additionalProperty" all_properties + testCase "derivesFrom" <| fun _ -> Expect.LDNodeHasDynamicProperty "derivesFrom" "derivesFrom" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/Sample" "sample_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "bioschemas.org/Sample" "sample_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/Sample"|] "sample_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"bioschemas.org/Sample"|] "sample_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -45,7 +45,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -60,7 +60,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -77,13 +77,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/ScholarlyArticle.Tests.fs b/tests/ROCrate/ISAProfile/ScholarlyArticle.Tests.fs index ea2c1168..e6544b57 100644 --- a/tests/ROCrate/ISAProfile/ScholarlyArticle.Tests.fs +++ b/tests/ROCrate/ISAProfile/ScholarlyArticle.Tests.fs @@ -16,7 +16,7 @@ let all_properties = ScholarlyArticle( id = "scholarlyarticle_all_properties_id", headline = "headline", identifier = "identifier", - additionalType = "additionalType", + additionalType = ResizeArray([|"additionalType"|]), author = "author", url = "url", creativeWorkStatus = "creativeWorkStatus", @@ -25,27 +25,27 @@ let all_properties = ScholarlyArticle( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "scholarlyarticle_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/ScholarlyArticle" mandatory_properties - testCase "headline" <| fun _ -> Expect.LDObjectHasDynamicProperty "headline" "headline" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "scholarlyarticle_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/ScholarlyArticle" mandatory_properties + testCase "headline" <| fun _ -> Expect.LDNodeHasDynamicProperty "headline" "headline" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "scholarlyarticle_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/ScholarlyArticle" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - testCase "headline" <| fun _ -> Expect.LDObjectHasDynamicProperty "headline" "headline" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties - testCase "author" <| fun _ -> Expect.LDObjectHasDynamicProperty "author" "author" all_properties - testCase "url" <| fun _ -> Expect.LDObjectHasDynamicProperty "url" "url" all_properties - testCase "creativeWorkStatus" <| fun _ -> Expect.LDObjectHasDynamicProperty "creativeWorkStatus" "creativeWorkStatus" all_properties - testCase "disambiguatingDescription" <| fun _ -> Expect.LDObjectHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "scholarlyarticle_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/ScholarlyArticle" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + testCase "headline" <| fun _ -> Expect.LDNodeHasDynamicProperty "headline" "headline" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties + testCase "author" <| fun _ -> Expect.LDNodeHasDynamicProperty "author" "author" all_properties + testCase "url" <| fun _ -> Expect.LDNodeHasDynamicProperty "url" "url" all_properties + testCase "creativeWorkStatus" <| fun _ -> Expect.LDNodeHasDynamicProperty "creativeWorkStatus" "creativeWorkStatus" all_properties + testCase "disambiguatingDescription" <| fun _ -> Expect.LDNodeHasDynamicProperty "disambiguatingDescription" "disambiguatingDescription" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/ScholarlyArticle" "scholarlyarticle_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/ScholarlyArticle" "scholarlyarticle_all_properties_id" (Some "additionalType") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/ScholarlyArticle"|] "scholarlyarticle_mandatory_properties_id" [||] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/ScholarlyArticle"|] "scholarlyarticle_all_properties_id" [|"additionalType"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -53,7 +53,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -68,7 +68,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -85,13 +85,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/ISAProfile/Study.Tests.fs b/tests/ROCrate/ISAProfile/Study.Tests.fs index b987aef2..e1be7864 100644 --- a/tests/ROCrate/ISAProfile/Study.Tests.fs +++ b/tests/ROCrate/ISAProfile/Study.Tests.fs @@ -29,33 +29,33 @@ let all_properties = Study( let tests_profile_object_is_valid = testList "constructed properties" [ testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "study_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" mandatory_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Study" mandatory_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" mandatory_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "study_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" mandatory_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Study" mandatory_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" mandatory_properties ] testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "study_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "schema.org/Dataset" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "Study" all_properties - testCase "identifier" <| fun _ -> Expect.LDObjectHasDynamicProperty "identifier" "identifier" all_properties - testCase "about" <| fun _ -> Expect.LDObjectHasDynamicProperty "about" "about" all_properties - testCase "citation" <| fun _ -> Expect.LDObjectHasDynamicProperty "citation" "citation" all_properties - testCase "comment" <| fun _ -> Expect.LDObjectHasDynamicProperty "comment" "comment" all_properties - testCase "creator" <| fun _ -> Expect.LDObjectHasDynamicProperty "creator" "creator" all_properties - testCase "dateCreated" <| fun _ -> Expect.LDObjectHasDynamicProperty "dateCreated" "dateCreated" all_properties - testCase "dateModified" <| fun _ -> Expect.LDObjectHasDynamicProperty "dateModified" "dateModified" all_properties - testCase "datePublished" <| fun _ -> Expect.LDObjectHasDynamicProperty "datePublished" "datePublished" all_properties - testCase "description" <| fun _ -> Expect.LDObjectHasDynamicProperty "description" "description" all_properties - testCase "hasPart" <| fun _ -> Expect.LDObjectHasDynamicProperty "hasPart" "hasPart" all_properties - testCase "headline" <| fun _ -> Expect.LDObjectHasDynamicProperty "headline" "headline" all_properties - testCase "url" <| fun _ -> Expect.LDObjectHasDynamicProperty "url" "url" all_properties + testCase "Id" <| fun _ -> Expect.LDNodeHasId "study_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "schema.org/Dataset" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "Study" all_properties + testCase "identifier" <| fun _ -> Expect.LDNodeHasDynamicProperty "identifier" "identifier" all_properties + testCase "about" <| fun _ -> Expect.LDNodeHasDynamicProperty "about" "about" all_properties + testCase "citation" <| fun _ -> Expect.LDNodeHasDynamicProperty "citation" "citation" all_properties + testCase "comment" <| fun _ -> Expect.LDNodeHasDynamicProperty "comment" "comment" all_properties + testCase "creator" <| fun _ -> Expect.LDNodeHasDynamicProperty "creator" "creator" all_properties + testCase "dateCreated" <| fun _ -> Expect.LDNodeHasDynamicProperty "dateCreated" "dateCreated" all_properties + testCase "dateModified" <| fun _ -> Expect.LDNodeHasDynamicProperty "dateModified" "dateModified" all_properties + testCase "datePublished" <| fun _ -> Expect.LDNodeHasDynamicProperty "datePublished" "datePublished" all_properties + testCase "description" <| fun _ -> Expect.LDNodeHasDynamicProperty "description" "description" all_properties + testCase "hasPart" <| fun _ -> Expect.LDNodeHasDynamicProperty "hasPart" "hasPart" all_properties + testCase "headline" <| fun _ -> Expect.LDNodeHasDynamicProperty "headline" "headline" all_properties + testCase "url" <| fun _ -> Expect.LDNodeHasDynamicProperty "url" "url" all_properties ] ] let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "study_mandatory_properties_id" (Some "Study") mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "schema.org/Dataset" "study_all_properties_id" (Some "Study") all_properties + testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "study_mandatory_properties_id" [|"Study"|] mandatory_properties + testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"schema.org/Dataset"|] "study_all_properties_id" [|"Study"|] all_properties ] let tests_dynamic_members = testSequenced ( @@ -63,7 +63,7 @@ let tests_dynamic_members = testSequenced ( testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" testCase "Set dynamic property" <| fun _ -> mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties testCase "Remove dynamic property" <| fun _ -> mandatory_properties.RemoveProperty("yes") |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" @@ -78,7 +78,7 @@ let tests_instance_methods = testSequenced ( testCase "can set context" <| fun _ -> mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> let ctx = mandatory_properties.TryGetContext() Expect.equal ctx (Some context) "context was not set correctly" @@ -114,13 +114,13 @@ let tests_static_methods = testSequenced ( context.SetProperty("more", "context") testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties + let ctx = LDNode.tryGetContext() mandatory_properties Expect.equal ctx (Some context) "context was not set correctly" testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore + LDNode.removeContext() mandatory_properties |> ignore Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" ] ) diff --git a/tests/ROCrate/LDContext.Tests.fs b/tests/ROCrate/LDContext.Tests.fs new file mode 100644 index 00000000..8a7359ed --- /dev/null +++ b/tests/ROCrate/LDContext.Tests.fs @@ -0,0 +1,214 @@ +module Tests.LDContext + +open ARCtrl.ROCrate +open DynamicObj + +open TestingUtils +open Common + +let schemaTerm = "schema" +let schemaIRI = "http://schema.org/" + +let nameTerm = "name" +let nameIRI = "http://schema.org/name" +let nameCompactIRI = "schema:name" + +let nameIRIAlternative = "http://fantasy-site.org/name" + + +let tests_equal = testList "Equality" [ + testCase "empty" <| fun _ -> + let context1 = new LDContext() + let context2 = new LDContext() + Expect.equal context1 context2 "empty contexts were not equal" + testCase "hasKeys_vs_empty" <| fun _ -> + let context1 = new LDContext() + context1.AddMapping(nameTerm, nameIRI) + let context2 = new LDContext() + Expect.notEqual context1 context2 "contexts with different keys were equal" + testCase "differentKeys" <| fun _ -> + let context1 = new LDContext() + context1.AddMapping(nameTerm, nameIRI) + let context2 = new LDContext() + context2.AddMapping(nameTerm, nameIRIAlternative) + Expect.notEqual context1 context2 "contexts with different keys were equal" + testCase "sameKeys" <| fun _ -> + let context1 = new LDContext() + context1.AddMapping(nameTerm, nameIRI) + let context2 = new LDContext() + context2.AddMapping(nameTerm, nameIRI) + Expect.equal context1 context2 "contexts with same keys were not equal" +] + +let tests_resolveTerm = testList "resolveTerm" [ + testCase "null" <| fun _ -> + let context = new LDContext() + let resolved = context.TryResolveTerm(nameTerm) + Expect.isNone resolved "missing term was resolved" + testCase "fullIRI" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let resolved = context.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "compactIRI" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameCompactIRI) + context.AddMapping(schemaTerm, schemaIRI) + let resolved = context.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "Nested_Shadowed" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + outerContext.AddMapping(nameTerm, nameIRIAlternative) + let resolved = outerContext.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRIAlternative "term was not resolved correctly" + testCase "Nested" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let resolved = outerContext.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" +] + +let tests_getTerm = testList "getTerm" [ + testCase "null" <| fun _ -> + let context = new LDContext() + let resolved = context.TryGetTerm(nameIRI) + Expect.isNone resolved "missing term was resolved" + testCase "fullIRI" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let resolved = context.TryGetTerm(nameIRI) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameTerm "term was not resolved correctly" + testCase "compactIRI" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameCompactIRI) + context.AddMapping(schemaTerm, schemaIRI) + let resolved = context.TryGetTerm(nameIRI) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameTerm "term was not resolved correctly" + testCase "compactIRI_reverseOrder" <| fun _ -> + let context = new LDContext() + context.AddMapping(schemaTerm, schemaIRI) + context.AddMapping(nameTerm, nameCompactIRI) + let resolved = context.TryGetTerm(nameIRI) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameTerm "term was not resolved correctly" + testCase "Nested_Shadowed" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + outerContext.AddMapping(nameTerm, nameIRIAlternative) + let resolved = outerContext.TryGetTerm(nameIRI) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameTerm "term was not resolved correctly" + testCase "Nested" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let resolved = outerContext.TryGetTerm(nameIRI) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameTerm "term was not resolved correctly" +] + +let tests_shallowCopy = testList "shallowCopy" [ + testCase "empty" <| fun _ -> + let context = new LDContext() + let copy = context.ShallowCopy() + Expect.isEmpty copy.Mappings "shallow copy was not empty" + testCase "empty_immutable" <| fun _ -> + let context = new LDContext() + let copy = context.ShallowCopy() + context.AddMapping(nameTerm, nameIRI) + Expect.isEmpty copy.Mappings "shallow copy was not empty" + testCase "withMapping" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let copy = context.ShallowCopy() + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withMapping_immutable" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let copy = context.ShallowCopy() + context.AddMapping(nameTerm, nameIRIAlternative) + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withBaseContext" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let copy = outerContext.ShallowCopy() + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withBaseContext_mutable" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let copy = outerContext.ShallowCopy() + innerContext.AddMapping(nameTerm, nameIRIAlternative) + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRIAlternative "term was not resolved correctly" +] + +let tests_deepCopy = testList "deepCopy" [ + testCase "empty" <| fun _ -> + let context = new LDContext() + let copy = context.DeepCopy() + Expect.isEmpty copy.Mappings "deep copy was not empty" + testCase "empty_immutable" <| fun _ -> + let context = new LDContext() + let copy = context.DeepCopy() + context.AddMapping(nameTerm, nameIRI) + Expect.isEmpty copy.Mappings "deep copy was not empty" + testCase "withMapping" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let copy = context.DeepCopy() + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withMapping_immutable" <| fun _ -> + let context = new LDContext() + context.AddMapping(nameTerm, nameIRI) + let copy = context.DeepCopy() + context.AddMapping(nameTerm, nameIRIAlternative) + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withBaseContext" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let copy = outerContext.DeepCopy() + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" + testCase "withBaseContext_immutable" <| fun _ -> + let innerContext = new LDContext() + innerContext.AddMapping(nameTerm, nameIRI) + let outerContext = new LDContext(baseContexts = ResizeArray [innerContext]) + let copy = outerContext.DeepCopy() + innerContext.AddMapping(nameTerm, nameIRIAlternative) + let resolved = copy.TryResolveTerm(nameTerm) + let resolved = Expect.wantSome resolved "term was not resolved" + Expect.equal resolved nameIRI "term was not resolved correctly" +] + +let main = testList "LDContext" [ + tests_equal + tests_resolveTerm + tests_getTerm + tests_shallowCopy + tests_deepCopy +] \ No newline at end of file diff --git a/tests/ROCrate/LDNode.Tests.fs b/tests/ROCrate/LDNode.Tests.fs new file mode 100644 index 00000000..e5cd2d2c --- /dev/null +++ b/tests/ROCrate/LDNode.Tests.fs @@ -0,0 +1,881 @@ +module Tests.LDNode + +open ARCtrl.ROCrate +open DynamicObj + +open TestingUtils +open Common +open ARCtrl.Helper + +let context = + new LDContext() + //|> DynObj.withProperty "more" "context" + +let thingType() = ResizeArray ["https://schema.org/Thing"] + +context.AddMapping("more","context") + +let mandatory_properties = LDNode("LDNode_mandatory_properties_id", ResizeArray[|"someType"|]) +let mandatory_properties_with_context = + LDNode("LDNode_mandatory_properties_id", ResizeArray[|"someType"|]) + |> DynObj.withProperty "@context" context + +let all_properties = LDNode("LDNode_all_properties_id", ResizeArray[|"someType"|], additionalType = ResizeArray[|"additionalType"|]) +let all_properties_with_context = + LDNode("LDNode_all_properties_id", ResizeArray[|"someType"|], additionalType = ResizeArray[|"additionalType"|]) + |> DynObj.withProperty "@context" (context.DeepCopy()) + +let tests_profile_object_is_valid = testList "constructed properties" [ + testList "mandatory properties" [ + testCase "Id" <| fun _ -> Expect.LDNodeHasId "LDNode_mandatory_properties_id" mandatory_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "someType" mandatory_properties + ] + testList "all properties" [ + testCase "Id" <| fun _ -> Expect.LDNodeHasId "LDNode_all_properties_id" all_properties + testCase "SchemaType" <| fun _ -> Expect.LDNodeHasType "someType" all_properties + testCase "AdditionalType" <| fun _ -> Expect.LDNodeHasAdditionalType "additionalType" all_properties + ] +] + +//let tests_interface_members = testList "interface members" [ +// testCase "mandatoryProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"someType"|] "LDNode_mandatory_properties_id" [||] mandatory_properties +// testCase "allProperties" <| fun _ -> Expect.LDNodeHasExpectedInterfaceMembers [|"someType"|] "LDNode_all_properties_id" [|"additionalType"|] all_properties +//] + +let tests_dynamic_members = testSequenced ( + testList "dynamic members" [ + testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" + testCase "Set dynamic property" <| fun _ -> + mandatory_properties.SetProperty("yes",42) + Expect.LDNodeHasDynamicProperty "yes" 42 mandatory_properties + testCase "Remove dynamic property" <| fun _ -> + mandatory_properties.RemoveProperty("yes") |> ignore + Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" + ] +) + +let tests_instance_methods = testSequenced ( + testList "instance methods" [ + + let context = new LDContext() + context.AddMapping("more", "context") + + testCase "can set context" <| fun _ -> + mandatory_properties.SetContext context + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties + testCase "can get context" <| fun _ -> + let ctx = mandatory_properties.TryGetContext() + Expect.equal ctx (Some context) "context was not set correctly" + testCase "can remove context" <| fun _ -> + mandatory_properties.RemoveContext() |> ignore + Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" + ] +) + +let tests_static_methods = testSequenced ( + testList "static methods" [ + testList "context" [ + let context = new LDContext() + context.AddMapping("more", "context") + + testCase "can set context" <| fun _ -> + LDNode.setContext context mandatory_properties + Expect.LDNodeHasDynamicProperty "@context" context mandatory_properties + testCase "can get context" <| fun _ -> + let ctx = LDNode.tryGetContext() mandatory_properties + Expect.equal ctx (Some context) "context was not set correctly" + testCase "can remove context" <| fun _ -> + LDNode.removeContext() mandatory_properties |> ignore + Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" + ] + testList "tryFromDynamicObj" [ + let compatibleDynObj = + let tmp = DynamicObj() + tmp + |> DynObj.withProperty "@type" "someType" + |> DynObj.withProperty "@id" "LDNode_all_properties_id" + |> DynObj.withProperty "additionalType" "additionalType" + + let compatibleDynObjWithContext = + let tmp = DynamicObj() + tmp + |> DynObj.withProperty "@type" "someType" + |> DynObj.withProperty "@id" "LDNode_all_properties_id" + |> DynObj.withProperty "additionalType" "additionalType" + |> DynObj.withProperty "@context" context + + let incompatibleDynObj = + let tmp = DynamicObj() + tmp + |> DynObj.withProperty "@type" "someType" + + testCase "can convert compatible DynObj to LDNode" <| fun _ -> + let roc = Expect.wantSome (LDNode.tryFromDynamicObj compatibleDynObj) "LDNode.tryFromDynamicObj did not return Some" + Expect.equal roc all_properties "LDNode was not created correctly from compatible DynamicObj" + testCase "can convert compatible DynObj with context to LDNode" <| fun _ -> + let roc = Expect.wantSome (LDNode.tryFromDynamicObj compatibleDynObjWithContext) "LDNode.tryFromDynamicObj did not return Some" + Expect.equal roc all_properties_with_context "LDNode was not created correctly from compatible DynamicObj" + testCase "cannot convert incompatible DynObj to LDNode" <| fun _ -> + Expect.isNone (LDNode.tryFromDynamicObj incompatibleDynObj) "LDNode.tryFromDynamicObj did not return None" + ] + ] +) + +let tests_TryGetProperty = testList "TryGetProperty" [ + testList "NoContext" [ + testCase "null" <| fun _ -> + let node = new LDNode("MyNode",ResizeArray ["https://schema.org/Thing"]) + let v = node.TryGetProperty("MyProperty") + Expect.isNone v "missing property was resolved" + testCase "fullIRI" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let nameKey = "https://schema.org/name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty(nameKey) + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + testCase "Term" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let nameKey = "name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty(nameKey) + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + ] + testList "SimpleContext" [ + testCase "null" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let v = node.TryGetProperty("name") + Expect.isNone v "missing property was resolved" + testCase "IRISet_TermGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let nameKey = "https://schema.org/name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty("name") + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + testCase "TermSet_TermGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let nameKey = "name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty("name") + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + testCase "IRISet_IRIGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let nameKey = "https://schema.org/name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty(nameKey) + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + testCase "TermSet_IRIGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let nameKey = "name" + let nameValue = "MyName" + node.SetProperty(nameKey, nameValue) + let v = node.TryGetProperty("https://schema.org/name") + let v = Expect.wantSome v "property was not resolved" + Expect.equal v nameValue "property was not resolved correctly" + ] + ] + +let tests_HasType = testList "HasType" [ + testList "NoContext" [ + testCase "null" <| fun _ -> + let node = new LDNode("MyNode",ResizeArray ["https://schema.org/Thing"]) + let v = node.HasType("https://schema.org/Person") + Expect.isFalse v "missing type was resolved" + testCase "fullIRI" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let v = node.HasType("https://schema.org/Thing") + Expect.isTrue v "type was not resolved" + testCase "Term" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["Thing"]) + let v = node.HasType("Thing") + Expect.isTrue v "type was not resolved" + ] + testList "SimpleContext" [ + testCase "null" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let v = node.HasType("https://schema.org/Person") + Expect.isFalse v "missing type was resolved" + testCase "IRISet_IRIGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let v = node.HasType("https://schema.org/Thing") + Expect.isTrue v "type was not resolved" + testCase "TermSet_TermGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + let node = new LDNode("MyNode", ResizeArray ["Thing"],context = context) + let v = node.HasType("Thing") + Expect.isTrue v "type was not resolved" + testCase "IRISet_TermGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"],context = context) + let v = node.HasType("Thing") + Expect.isTrue v "type was not resolved" + testCase "TermSet_IRIGet" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + let node = new LDNode("MyNode", ResizeArray ["Thing"],context = context) + let v = node.HasType("https://schema.org/Thing") + Expect.isTrue v "type was not resolved" + testCase "MultiType" <| fun _ -> + let context = new LDContext() + context.AddMapping("Thing", "https://schema.org/Thing") + context.AddMapping("Person", "https://schema.org/Person") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing";"https://schema.org/Person"],context = context) + let v = node.HasType("https://schema.org/Thing") + Expect.isTrue v "Thing IRI was not resolved" + let v = node.HasType("https://schema.org/Person") + Expect.isTrue v "Person IRI was not resolved" + let v = node.HasType("Thing") + Expect.isTrue v "Thing Term was not resolved" + let v = node.HasType("Person") + Expect.isTrue v "Person Term was not resolved" + ] +] + + + +let tests_GetPropertyValues = testList "GetPropertyValues" [ + testCase "null" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let v = node.GetPropertyValues("https://schema.org/name") + Expect.isEmpty v "missing type was resolved" + testCase "StringSequence" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let values = seq {"Name1";"Name2"} + node.SetProperty("https://schema.org/name", values) + let v = node.GetPropertyValues("https://schema.org/name") |> ResizeArray.map (fun x -> x :?> string) + Expect.sequenceEqual v values "values were not resolved" + testCase "StringArray" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let values = ResizeArray ["Name1";"Name2"] + node.SetProperty("https://schema.org/name", values) + let v = node.GetPropertyValues("https://schema.org/name") |> ResizeArray.map (fun x -> x :?> string) + Expect.sequenceEqual v values "values were not resolved" + testCase "SingleString" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let value = "Name1" + node.SetProperty("https://schema.org/name", value) + let v = node.GetPropertyValues("https://schema.org/name") |> ResizeArray.map (fun x -> x :?> string) + Expect.sequenceEqual v (ResizeArray [value]) "values were not resolved" + testCase "SingleNode" <| fun _ -> + let internalNode1 = new LDNode("MyNode1", ResizeArray ["https://schema.org/Thing"]) + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", internalNode1) + let v = node.GetPropertyValues("https://schema.org/about") |> ResizeArray.map (fun x -> x :?> LDNode) + Expect.sequenceEqual v (ResizeArray [internalNode1]) "values were not resolved" + testList "Filter" [ + testCase "OnlyRetrieveNumbers" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let values : ResizeArray = ResizeArray [box "Name1";3;4;"Name2"] + node.SetProperty("https://schema.org/name", values) + let filter = fun (x : obj) _ -> x :? int + let v = node.GetPropertyValues("https://schema.org/name", filter = filter) |> ResizeArray.map (fun x -> x :?> int) + Expect.sequenceEqual v (ResizeArray [3;4]) "values were not resolved" + ] +] + +let tests_GetPropertyNodes = testList "GetPropertyNodes" [ + testCase "null" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let v = node.GetPropertyNodes("https://schema.org/name") + Expect.isEmpty v "missing type was resolved" + testCase "SequenceSet" <| fun _ -> + let internalNode1 = new LDNode("MyNode1",ResizeArray ["https://schema.org/Thing"]) + let internalNode2 = new LDNode("MyNode2",ResizeArray ["https://schema.org/Thing"]) + let values = seq {internalNode1;internalNode2} + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", values) + let v = node.GetPropertyNodes("https://schema.org/about") + Expect.sequenceEqual v (ResizeArray [internalNode1;internalNode2]) "values were not resolved" + testCase "IgnoreNonNodes" <| fun _ -> + let internalNode1 = new LDNode("MyNode1",ResizeArray ["https://schema.org/Thing"]) + let internalNode2 = new LDNode("MyNode2",ResizeArray ["https://schema.org/Thing"]) + let values : seq = seq {internalNode1 |> box;5;internalNode2;"NotANode"} + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", values) + let v = node.GetPropertyNodes("https://schema.org/about") + Expect.sequenceEqual v (ResizeArray [internalNode1;internalNode2]) "values were not resolved" + ptestCase "Flattened_NoGraph" <| fun _ -> + let internalNode1 = new LDNode("MyNode1",ResizeArray ["https://schema.org/Thing"]) + let internalNode2 = new LDNode("MyNode2",ResizeArray ["https://schema.org/Thing"]) + let values = seq {internalNode1;internalNode2} + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", values) + let graph = node.Flatten() + let f () = node.GetPropertyNodes("https://schema.org/about") |> ignore + Expect.throws f "Should fail, as LDRefs can't be resolved" // Or maybe not? Setting this to pending for now + testCase "Flattened_WithGraph" <| fun _ -> + let internalNode1 = new LDNode("MyNode1",ResizeArray ["https://schema.org/Thing"]) + let internalNode2 = new LDNode("MyNode2",ResizeArray ["https://schema.org/Thing"]) + let values = seq {internalNode1;internalNode2} + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", values) + let graph = node.Flatten() + let v = node.GetPropertyNodes("https://schema.org/about", graph = graph) + Expect.sequenceEqual v (ResizeArray [internalNode1;internalNode2]) "values were not resolved" + testList "Filter" [ + testCase "FilterForType" <| fun _ -> + let internalNode1 = new LDNode("MyNode1", ResizeArray ["https://schema.org/Person"]) + let internalNode2 = new LDNode("MyNode2", ResizeArray ["https://schema.org/CreativeWork"]) + let values = ResizeArray [internalNode1;internalNode2] + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", values) + let filter = fun (x : LDNode) _ -> x.HasType("https://schema.org/Person") + let v = node.GetPropertyNodes("https://schema.org/about", filter = filter) + Expect.sequenceEqual v (ResizeArray [internalNode1]) "values were not resolved" + ] +] + +let tests_TryGetPropertyAsSingleNode = testList "TryGetPropertyAsSingleNode" [ + testCase "PropertyDoesNotExist" <| fun _ -> + let node = new LDNode(id = "MyNode", schemaType = ResizeArray ["https://schema.org/Thing"]) + let v = node.TryGetPropertyAsSingleNode("name") + Expect.isNone v "property was resolved" + testCase "PropertyIsNotNode" <| fun _ -> + let node = new LDNode(id = "MyNode", schemaType = ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("name", "MyName") + let v = node.TryGetPropertyAsSingleNode("name") + Expect.isNone v "property was resolved" + testCase "PropertyIsNode" <| fun _ -> + let internalNode = new LDNode(id = "MyInternal", schemaType = ResizeArray ["https://schema.org/Thing"]) + let node = new LDNode(id = "MyNode", schemaType = ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("about", internalNode) + let v = Expect.wantSome (node.TryGetPropertyAsSingleNode("about")) "property was not resolved" + Expect.equal v internalNode "property was not resolved correctly" + testCase "PropertyIsLDRef_NoGraph" <| fun _ -> + let node = new LDNode(id = "MyNode", schemaType = ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("about", LDRef("MyInternal")) + let v = node.TryGetPropertyAsSingleNode("about") + Expect.isNone v "property was resolved" + testCase "PropertyIsLDRef_WithGraph" <| fun _ -> + let internalNode = new LDNode(id = "MyInternal", schemaType = ResizeArray ["https://schema.org/Thing"]) + let graph = new LDGraph() + graph.AddNode(internalNode) + let node = new LDNode(id = "MyNode", schemaType = ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("about", LDRef("MyInternal")) + let v = Expect.wantSome (node.TryGetPropertyAsSingleNode("about", graph = graph)) "property was not resolved" + Expect.equal v internalNode "property was not resolved correctly" + ] + +let tests_Compact_InPlace = testList "Compact_InPlace" [ + testCase "Type_SetContextTrue" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let context = new LDContext() + context.AddMapping("thing", "https://schema.org/Thing") + node.Compact_InPlace(context,setContext=true) + let ctx = Expect.wantSome (node.TryGetContext()) "context was not set" + Expect.equal (ctx.TryResolveTerm("thing")) (Some "https://schema.org/Thing") "context was not set correctly" + testCase "Type_SetContextFalse" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let context = new LDContext() + context.AddMapping("thing", "https://schema.org/Thing") + node.Compact_InPlace(context,setContext=false) + Expect.isNone (node.TryGetContext()) "context was set" + testCase "Type" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let context = new LDContext() + context.AddMapping("thing", "https://schema.org/Thing") + node.Compact_InPlace(context) + Expect.sequenceEqual node.SchemaType ["thing"] "type was not compacted" + testCase "StringValue" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let value = LDValue("MyValue") + node.SetProperty("https://schema.org/name", value) + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + node.Compact_InPlace(context) + // Check compaction of value object to value + let v = Expect.wantSome (node.TryGetProperty("name")) "property does not exist anymore" + Expect.equal v "MyValue" "property value was not compacted" + // Check compaction of property name + Expect.isTrue ((node :> DynamicObj).HasProperty("name")) "compacted property was not found" + Expect.isFalse((node :> DynamicObj).HasProperty("https://schema.org/name")) "property name was not compacted" + testCase "IntValue" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let value = LDValue(42) + node.SetProperty("https://schema.org/age", value) + let context = new LDContext() + context.AddMapping("age", "https://schema.org/age") + node.Compact_InPlace(context) + // Check compaction of value object to value + let v = Expect.wantSome (node.TryGetProperty("age")) "property does not exist anymore" + Expect.equal v 42 "property value was not compacted" + // Check compaction of property name + Expect.isTrue ((node :> DynamicObj).HasProperty("age")) "compacted property was not found" + Expect.isFalse((node :> DynamicObj).HasProperty("https://schema.org/age")) "property name was not compacted" + testCase "NodeValue_Recursive" <| fun _ -> + let internalNode = new LDNode("MyInternalNode", ResizeArray ["https://schema.org/Thing"]) + let internalValue = LDValue("MyName") + internalNode.SetProperty("https://schema.org/name", internalValue) + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", internalNode) + let context = new LDContext() + context.AddMapping("about", "https://schema.org/about") + context.AddMapping("name", "https://schema.org/name") + node.Compact_InPlace(context) + // Check compaction of outer node + let internalNode = Expect.wantSome (node.TryGetProperty("about")) "outer property does not exist anymore" + Expect.isTrue ((node :> DynamicObj).HasProperty("about")) "outer compacted property was not found" + Expect.isFalse((node :> DynamicObj).HasProperty("https://schema.org/about")) "outer property name was not compacted" + // Check compaction of outer node + let internalNode = internalNode :?> LDNode + let v = Expect.wantSome (internalNode.TryGetProperty("name")) "inner property does not exist anymore" + Expect.equal v "MyName" "inner property value was not compacted" + Expect.isTrue ((internalNode :> DynamicObj).HasProperty("name")) "inner compacted property was not found" + Expect.isFalse((internalNode :> DynamicObj).HasProperty("https://schema.org/name")) "inner property name was not compacted" + ] + +let tests_Flatten = testList "Flatten" [ + testCase "EmptyNode" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let graph = node.Flatten() + Expect.sequenceEqual graph.Nodes [node] "graph was not flattened" + testCase "SingleNodeValue_Recursive" <| fun _ -> + let internalNode = new LDNode("MyInternalNode", ResizeArray ["https://schema.org/Thing"]) + let internalValue = "MyName" + internalNode.SetProperty("https://schema.org/name", internalValue) + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", internalNode) + let graph = node.Flatten() + Expect.equal graph.Nodes.Count 2 "Graph should have two nodes" + let oNode = Expect.wantSome (graph.TryGetNode("MyNode")) "outer node was not found" + let nodeRef = Expect.wantSome (oNode.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.equal nodeRef (LDRef("MyInternalNode")) "property value was not replaced by id reference" + let iNode = Expect.wantSome (graph.TryGetNode("MyInternalNode")) "inner node was not found" + let v = Expect.wantSome (iNode.TryGetProperty("https://schema.org/name")) "inner property does not exist anymore" + Expect.equal v "MyName" "inner property value was not found" + testCase "PointsToTheSameEmptyNode" <| fun _ -> + let internalNode() = new LDNode("MyInternalNode", ResizeArray ["https://schema.org/Thing"]) + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", internalNode()) + node.SetProperty("https://schema.org/hasPart", internalNode()) + let graph = node.Flatten() + Expect.equal graph.Nodes.Count 2 "Graph should have two nodes" + let oNode = Expect.wantSome (graph.TryGetNode("MyNode")) "outer node was not found" + let nodeRef = Expect.wantSome (oNode.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.equal nodeRef (LDRef("MyInternalNode")) "property value was not replaced by id reference" + let nodeRef = Expect.wantSome (oNode.TryGetProperty("https://schema.org/hasPart")) "outer property should still reference inner node" + Expect.equal nodeRef (LDRef("MyInternalNode")) "property value was not replaced by id reference" + Expect.isSome (graph.TryGetNode("MyInternalNode")) "inner node was not found" + testCase "PointsToSameNodeWithDifferentProperties" <| fun _ -> + let internalNode1 = new LDNode("MyInternalNode", ResizeArray ["https://schema.org/Thing"]) + internalNode1.SetProperty("https://schema.org/name", "MyName") + let internalNode2 = new LDNode("MyInternalNode", ResizeArray ["https://schema.org/Thing"]) + internalNode2.SetProperty("https://schema.org/age", 42) + let node = new LDNode("MyNode" , ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/about", internalNode1) + node.SetProperty("https://schema.org/hasPart", internalNode2) + let graph = node.Flatten() + Expect.equal graph.Nodes.Count 2 "Graph should have 2 nodes" + let oNode = Expect.wantSome (graph.TryGetNode("MyNode")) "outer node was not found" + let nodeRef = Expect.wantSome (oNode.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.equal nodeRef (LDRef("MyInternalNode")) "property value was not replaced by id reference" + let nodeRef = Expect.wantSome (oNode.TryGetProperty("https://schema.org/hasPart")) "outer property should still reference inner node" + Expect.equal nodeRef (LDRef("MyInternalNode")) "property value was not replaced by id reference" + let iNode = Expect.wantSome (graph.TryGetNode("MyInternalNode")) "inner node was not found" + let v = Expect.wantSome (iNode.TryGetProperty("https://schema.org/name")) "inner property does not exist anymore" + Expect.equal v "MyName" "inner property value was not found" + let v = Expect.wantSome (iNode.TryGetProperty("https://schema.org/age")) "inner property does not exist anymore" + Expect.equal v 42 "inner property value was not found" + ] + +let tests_getPropertyNames = testList "GetPropertyNames" [ + testCase "EmptyNode" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + let names = node.GetPropertyNames() + Expect.isEmpty names "Empty node should have no properties" + testCase "NoContext" <| fun _ -> + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"]) + node.SetProperty("https://schema.org/name", "MyName") + let names = node.GetPropertyNames() + Expect.sequenceEqual names ["https://schema.org/name"] "Property name was not found" + testCase "WithContext" <| fun _ -> + let context = new LDContext() + context.AddMapping("name", "https://schema.org/name") + let node = new LDNode("MyNode", ResizeArray ["https://schema.org/Thing"], context = context) + node.SetProperty("https://schema.org/name", "MyName") + let names = node.GetPropertyNames() + Expect.sequenceEqual names ["https://schema.org/name"] "Property name was not found" +] + + +let tests_mergeAppendInto_InPlace = testList "mergeAppendInto_InPlace" [ + testCase "EmptyNodes" <| fun _ -> + let getNode1() = new LDNode("MyNode1", thingType()) + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.isEmpty (node2.GetPropertyNames()) "Should have no properties" + + testCase "DifferentKeys" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/age", 42) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/age"; "https://schema.org/name"] "Should have both Properties" + Expect.equal (node2.TryGetProperty("https://schema.org/age").Value) 42 "Property value was not copied" + Expect.equal (node2.TryGetProperty("https://schema.org/name").Value) "MyName" "Property value was not copied" + + testCase "SameKeys_SamePropertyValue" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", "MyName") + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + Expect.equal (node2.TryGetProperty("https://schema.org/name").Value) "MyName" "Property value should not have been modified" + + testCase "SameKeys_DifferentStringValue" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", "MyOtherName") + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["MyName";"MyOtherName"] "Property value should have been modified" + + testCase "SameKeys_StringVsInt" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", 50) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["MyName" |> box ;50] "Property value should have been modified" + + testCase "SameKeys_DifferentPropertyValue" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", "MyOtherName") + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["MyName";"MyOtherName"] "Property value should have been modified" + + testCase "SameKeys_ArrayVsString_NotExisting" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyOtherName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["Name1";"Name2";"MyOtherName"] "Property value should have been modified" + + testCase "SameKeys_ArrayVsString_Existing" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "Name1") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["Name1";"Name2"] "Property value should have been modified" + + testCase "SameKeys_ArrayVsInt_NotExisting" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", 3) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", [1;2]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value [1;2;3] "Property value should have been modified" + + testCase "SameKeys_ArrayVsInt_Existing" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", 1) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", [1;2]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value [1;2] "Property value should have been modified" + + testCase "SameKeys_ArraysWithDifferentValues" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", ["Name3";"Name4"]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["Name3";"Name4";"Name1";"Name2"] "Property value should have been modified" + + testCase "SameKeys_ArraysWithSameValues" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["Name1";"Name2"] "Property value should not have been modified" + + testCase "SameKeys_ArraysWithOverlappingValues" <| fun _ -> + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", ["Name1";"Name2"]) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/name", ["Name2";"Name3"]) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/name"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/name").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value ["Name2";"Name3";"Name1"] "Property value should not have been modified" + + testCase "SameKeys_LDNode_NotExisting" <| fun _ -> + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/about", "String54") + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/about").Value + Expect.isTrue (value :? System.Collections.IEnumerable) "Property value should now be sequence" + let value = (value :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual value [new LDNode("MyInternalNode", thingType()) |> box;"String54"] "Property value should have been modified" + + testCase "SameKeys_LDNode_AlreadyExisting" <| fun _ -> + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/about", new LDNode("MyInternalNode", thingType())) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/about").Value + Expect.equal value (new LDNode("MyInternalNode", thingType())) "Property value should have been modified" + + testCase "SameKeys_LDNodeLDRefExisting" <| fun _ -> + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/about", new LDRef("MyInternalNode")) + node1.MergeAppendInto_InPlace(node2) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + let value = node2.TryGetProperty("https://schema.org/about").Value + Expect.equal value (new LDRef("MyInternalNode")) "Property value should have been modified" + testList "WithGraph" [ + testCase "DifferentKeys_String" <| fun _ -> + let graph = new LDGraph() + let getNode1() = + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/name", "MyName") + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/age", 42) + node1.MergeAppendInto_InPlace(node2, flattenTo = graph) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/age"; "https://schema.org/name"] "Should have both Properties" + Expect.equal graph.Nodes.Count 0 "Graph should have 0 nodes" + + testCase "DifferentKeys_LDNode" <| fun _ -> + let graph = new LDGraph() + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/age", 42) + node1.MergeAppendInto_InPlace(node2, flattenTo = graph) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/age"; "https://schema.org/about"] "Should have both Properties" + Expect.equal graph.Nodes.Count 1 "Graph should have 1 node" + Expect.isSome (graph.TryGetNode("MyInternalNode")) "inner node was not found" + let ref = Expect.wantSome (node2.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.equal ref (LDRef("MyInternalNode")) "property value was not replaced by id reference" + testCase "SameKeys_SameLDNode" <| fun _ -> + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/about", new LDNode("MyInternalNode", thingType())) + let graph = node2.Flatten() + node1.MergeAppendInto_InPlace(node2, flattenTo = graph) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + Expect.equal graph.Nodes.Count 2 "Graph should have 2 nodes" + Expect.isSome (graph.TryGetNode("MyNode2")) "outer node was not found" + Expect.isSome (graph.TryGetNode("MyInternalNode")) "inner node was not found" + let ref = Expect.wantSome (node2.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.equal ref (LDRef("MyInternalNode")) "property value was not replaced by id reference" + testCase "SameKeys_DifferentLDNode" <| fun _ -> + let getNode1() = + let internalNode = new LDNode("MyInternalNode", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", internalNode) + n + let node1 = getNode1() + let node2 = new LDNode("MyNode2", thingType()) + node2.SetProperty("https://schema.org/about", new LDNode("MyOtherInternalNode", thingType())) + let graph = node2.Flatten() + node1.MergeAppendInto_InPlace(node2, flattenTo = graph) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + Expect.equal graph.Nodes.Count 3 "Graph should have 3 nodes" + Expect.isSome (graph.TryGetNode("MyNode2")) "outer node was not found" + Expect.isSome (graph.TryGetNode("MyInternalNode")) "inner node 1 was not found" + Expect.isSome (graph.TryGetNode("MyOtherInternalNode")) "inner node 2 was not found" + let refs = Expect.wantSome (node2.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.isTrue (refs :? System.Collections.IEnumerable) "Property value should now be sequence" + let refs = (refs :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual refs [LDRef("MyInternalNode");LDRef("MyOtherInternalNode")] "Property value should have been modified" + testCase "SameKey_NewLDNodeSeq" <| fun _ -> + let getNode1() = + let internalNode1 = new LDNode("MyInternalNode1", thingType()) + let internalNode2 = new LDNode("MyInternalNode2", thingType()) + let n = new LDNode("MyNode1", thingType()) + n.SetProperty("https://schema.org/about", [internalNode1;internalNode2]) + n + let node2 = new LDNode("MyNode2", thingType()) + let internalNode3 = new LDNode("MyInternalNode3", thingType()) + node2.SetProperty("https://schema.org/about", [internalNode3]) + let graph = node2.Flatten() + let node1 = getNode1() + node1.MergeAppendInto_InPlace(node2, flattenTo = graph) + Expect.equal node1 (getNode1()) "Node1 should not have changed modified" + Expect.sequenceEqual (node2.GetPropertyNames()) ["https://schema.org/about"] "Should have the Property" + Expect.equal graph.Nodes.Count 4 "Graph should have 4 nodes" + Expect.isSome (graph.TryGetNode("MyNode2")) "outer node was not found" + Expect.isSome (graph.TryGetNode("MyInternalNode1")) "inner node 1 was not found" + Expect.isSome (graph.TryGetNode("MyInternalNode2")) "inner node 2 was not found" + Expect.isSome (graph.TryGetNode("MyInternalNode3")) "inner node 3 was not found" + let refs = Expect.wantSome (node2.TryGetProperty("https://schema.org/about")) "outer property should still reference inner node" + Expect.isTrue (refs :? System.Collections.IEnumerable) "Property value should now be sequence" + let refs = (refs :?> System.Collections.IEnumerable) + Expect.genericSequenceEqual refs [LDRef("MyInternalNode3");LDRef("MyInternalNode1");LDRef("MyInternalNode2")] "Property value should have been modified" + ] + ] + +let main = testList "LDNode" [ + tests_profile_object_is_valid + //tests_interface_members + tests_dynamic_members + tests_instance_methods + tests_static_methods + tests_TryGetProperty + tests_HasType + tests_GetPropertyValues + tests_GetPropertyNodes + tests_TryGetPropertyAsSingleNode + tests_Compact_InPlace + tests_Flatten + tests_getPropertyNames + tests_mergeAppendInto_InPlace +] \ No newline at end of file diff --git a/tests/ROCrate/LDObject.Tests.fs b/tests/ROCrate/LDObject.Tests.fs deleted file mode 100644 index 658c7e1d..00000000 --- a/tests/ROCrate/LDObject.Tests.fs +++ /dev/null @@ -1,83 +0,0 @@ -module Tests.LDObject - -open ARCtrl.ROCrate -open DynamicObj - -open TestingUtils -open Common - -let mandatory_properties = LDObject("LDObject_mandatory_properties_id", "someType") -let all_properties = LDObject("LDObject_all_properties_id", "someType", additionalType = "additionalType") - -let tests_profile_object_is_valid = testList "constructed properties" [ - testList "mandatory properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "LDObject_mandatory_properties_id" mandatory_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "someType" mandatory_properties - ] - testList "all properties" [ - testCase "Id" <| fun _ -> Expect.LDObjectHasId "LDObject_all_properties_id" all_properties - testCase "SchemaType" <| fun _ -> Expect.LDObjectHasType "someType" all_properties - testCase "AdditionalType" <| fun _ -> Expect.LDObjectHasAdditionalType "additionalType" all_properties - ] -] - -let tests_interface_members = testList "interface members" [ - testCase "mandatoryProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "someType" "LDObject_mandatory_properties_id" None mandatory_properties - testCase "allProperties" <| fun _ -> Expect.LDObjectHasExpectedInterfaceMembers "someType" "LDObject_all_properties_id" (Some "additionalType") all_properties -] - -let tests_dynamic_members = testSequenced ( - testList "dynamic members" [ - testCase "property not present before setting" <| fun _ -> Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be set" - testCase "Set dynamic property" <| fun _ -> - mandatory_properties.SetProperty("yes",42) - Expect.LDObjectHasDynamicProperty "yes" 42 mandatory_properties - testCase "Remove dynamic property" <| fun _ -> - mandatory_properties.RemoveProperty("yes") |> ignore - Expect.isNone (DynObj.tryGetTypedPropertyValue "yes" mandatory_properties) "dynamic property 'yes' was set although it was expected not to be removed" - ] -) - -let tests_instance_methods = testSequenced ( - testList "instance methods" [ - - let context = new LDContext() - context.SetProperty("more", "context") - - testCase "can set context" <| fun _ -> - mandatory_properties.SetContext context - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties - testCase "can get context" <| fun _ -> - let ctx = mandatory_properties.TryGetContext() - Expect.equal ctx (Some context) "context was not set correctly" - testCase "can remove context" <| fun _ -> - mandatory_properties.RemoveContext() |> ignore - Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" - ] -) - -let tests_static_methods = testSequenced ( - testList "static methods" [ - - let context = new LDContext() - context.SetProperty("more", "context") - - testCase "can set context" <| fun _ -> - LDObject.setContext context mandatory_properties - Expect.LDObjectHasDynamicProperty "@context" context mandatory_properties - testCase "can get context" <| fun _ -> - let ctx = LDObject.tryGetContext() mandatory_properties - Expect.equal ctx (Some context) "context was not set correctly" - testCase "can remove context" <| fun _ -> - LDObject.removeContext() mandatory_properties |> ignore - Expect.isNone (DynObj.tryGetTypedPropertyValue "@context" mandatory_properties) "context was not removed correctly" - ] -) - -let main = testList "LDObject" [ - tests_profile_object_is_valid - tests_interface_members - tests_dynamic_members - tests_instance_methods - tests_static_methods -] \ No newline at end of file diff --git a/tests/ROCrate/Main.fs b/tests/ROCrate/Main.fs index 6f6df3c7..10dc29f5 100644 --- a/tests/ROCrate/Main.fs +++ b/tests/ROCrate/Main.fs @@ -3,18 +3,19 @@ module ARCtrl.ROCrate.Tests open Fable.Pyxpecto let all = testSequenced <| testList "ROCrate" [ - Tests.LDObject.main - Tests.Dataset.main - Tests.Investigation.main - Tests.Study.main - Tests.Assay.main - Tests.LabProcess.main - Tests.LabProtocol.main - Tests.Sample.main - Tests.Data.main - Tests.PropertyValue.main - Tests.Person.main - Tests.ScholarlyArticle.main + Tests.LDContext.main + Tests.LDNode.main + //Tests.Dataset.main + //Tests.Investigation.main + //Tests.Study.main + //Tests.Assay.main + //Tests.LabProcess.main + //Tests.LabProtocol.main + //Tests.Sample.main + //Tests.Data.main + //Tests.PropertyValue.main + //Tests.Person.main + //Tests.ScholarlyArticle.main ] #if !TESTS_ALL diff --git a/tests/TestingUtils/TestObjects.Json/ROCrate.fs b/tests/TestingUtils/TestObjects.Json/ROCrate.fs index 4d403ca6..7381b3fe 100644 --- a/tests/TestingUtils/TestObjects.Json/ROCrate.fs +++ b/tests/TestingUtils/TestObjects.Json/ROCrate.fs @@ -1,24 +1,49 @@ /// All json objects tested against offical validator: https://validator.schema.org module TestObjects.Json.ROCrate -let definedTerm = """{ - "@id": "http://purl.obolibrary.org/obo/NCIT_C16965", - "@type": "OntologyAnnotation", - "annotationValue": "Peptidase", - "termSource": "MS", - "termAccession": "http://purl.obolibrary.org/obo/NCIT_C16965", - "comments": [ - "Comment {Name = \"comment\", Value= \"This is a comment\"}" - ], - "@context": { - "sdo": "http://schema.org/", - "OntologyAnnotation": "sdo:DefinedTerm", - "annotationValue": "sdo:name", - "termSource": "sdo:inDefinedTermSet", - "termAccession": "sdo:termCode", - "comments": "sdo:disambiguatingDescription" - } -}""" +let context_DefinedTerm = + """{ + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + }""" + +let definedTerm = + context_DefinedTerm + |> sprintf """{ + "@id": "http://purl.obolibrary.org/obo/NCIT_C16965", + "@type": "OntologyAnnotation", + "annotationValue": "Peptidase", + "termSource": "MS", + "termAccession": "http://purl.obolibrary.org/obo/NCIT_C16965", + "comments": [ + "Comment {Name = \"comment\", Value= \"This is a comment\"}" + ], + "@context": %s + }""" + + +let roCrate_minimal = """{ + "@context": "https://w3id.org/ro/crate/1.2-DRAFT/context", + "@graph": [ + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "about": {"@id": "./"}, + "conformsTo": {"@id": "https://w3id.org/ro/crate/1.2-DRAFT"} + }, + { + "@id": "./", + "@type": "Dataset" + } + ] + }""" + + + let propertyValue = """{ "@id": "http://purl.obolibrary.org/obo/NCIT_C16965", @@ -208,6 +233,12 @@ module GenericObjects = "@id": "MyIdentifier", "@type": "MyType" }""" + + let onlyIDAndTypeNoTypeArray = + """{ + "@id": "MyIdentifier", + "@type": "MyType" + }""" let onlyID = """{ @@ -219,6 +250,17 @@ module GenericObjects = "@type": "MyType" }""" + let twoTypesAndID = + """{ + "@id": "MyIdentifier", + "@type": ["MyType" , "MySecondType"] + }""" + + let onlyTypeNoTypeArray = + """{ + "@type": "MyType" + }""" + let withStringFields = """{ "@id": "MyIdentifier", @@ -227,6 +269,14 @@ module GenericObjects = "description": "MyDescription" }""" + let withStringFieldsNoTypeArray = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "name": "MyName", + "description": "MyDescription" + }""" + let withIntFields = """{ "@id": "MyIdentifier", @@ -234,6 +284,14 @@ module GenericObjects = "number": 42, "anotherNumber": 1337 }""" + + let withIntFieldsNoTypeArray = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "number": 42, + "anotherNumber": 1337 + }""" let withStringArray = """{ @@ -242,6 +300,49 @@ module GenericObjects = "names": ["MyName", "MySecondName"] }""" + let withStringArrayNoTypeArray = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "names": ["MyName", "MySecondName"] + }""" + + let withExpandedStringFieldNoType = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "name": { + "@value": "MyName" + } + }""" + + let withExpandedStringFieldWithType = """{ + "@id": "MyIdentifier", + "@type": "MyType", + "name": { + "@value": "MyName", + "@type": "http://www.w3.org/2001/XMLSchema#string" + } + }""" + + let withExpandedIntFieldWithType = """{ + "@id": "MyIdentifier", + "@type": "MyType", + "number": { + "@value": 42, + "@type": "http://www.w3.org/2001/XMLSchema#integer" + } + }""" + + let withLDRefObject = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "nested": { + "@id": "RefIdentifier" + } + }""" + let withNestedObject = sprintf """{ "@id": "OuterIdentifier", @@ -249,6 +350,13 @@ module GenericObjects = "nested": %s }""" onlyIDAndType + let withNestedObjectNoTypeArray = + sprintf """{ + "@id": "OuterIdentifier", + "@type": "MyType", + "nested": %s + }""" onlyIDAndTypeNoTypeArray + let withObjectArray = sprintf """{ "@id": "OuterIdentifier", @@ -256,9 +364,43 @@ module GenericObjects = "nested": [%s, %s] }""" onlyIDAndType onlyIDAndType + let withObjectArrayNoTypeArray = + sprintf """{ + "@id": "OuterIdentifier", + "@type": "MyType", + "nested": [%s, %s] + }""" onlyIDAndTypeNoTypeArray onlyIDAndTypeNoTypeArray + let withMixedArray = sprintf """{ "@id": "OuterIdentifier", "@type": "MyType", "nested": [%s, "Value2", 42] - }""" onlyIDAndType \ No newline at end of file + }""" onlyIDAndType + + let withMixedArrayNoTypeArray = + sprintf """{ + "@id": "OuterIdentifier", + "@type": "MyType", + "nested": [%s, "Value2", 42] + }""" onlyIDAndTypeNoTypeArray + + let withAdditionalTypeString = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "additionalType": "additionalType" + }""" + + let withAdditionalTypeArray = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "additionalType": ["additionalType"] + }""" + let withAddtionalTypeArrayMultipleEntries = + """{ + "@id": "MyIdentifier", + "@type": "MyType", + "additionalType": ["additionalType1", "additionalType2"] + }""" \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@70a7c83e7858a974bf913de2e27d8e44191fc73f.json b/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@70a7c83e7858a974bf913de2e27d8e44191fc73f.json deleted file mode 100644 index 380e2f56..00000000 --- a/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@70a7c83e7858a974bf913de2e27d8e44191fc73f.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "@type": "CreativeWork", - "@id": "ro-crate-metadata.json", - "about": { - "@id": "./", - "@type": "Investigation", - "additionalType": "Investigation", - "identifier": "ArcPrototype", - "filename": "isa.investigation.xlsx", - "title": "ArcPrototype", - "description": "A prototypic ARC that implements all specification standards accordingly", - "people": [ - { - "@id": "timo.muehlhaus@rptu.de", - "@type": "Person", - "orcid": "http://orcid.org/0000-0003-3925-6778", - "firstName": "Timo", - "lastName": "Mühlhaus", - "email": "timo.muehlhaus@rptu.de", - "phone": "0 49 (0)631 205 4657", - "address": "RPTU University of Kaiserslautern, Paul-Ehrlich-Str. 23 , 67663 Kaiserslautern", - "affiliation": { - "@type": "Organization", - "@id": "#Organization_RPTU_University_of_Kaiserslautern", - "name": "RPTU University of Kaiserslautern", - "@context": { - "sdo": "http://schema.org/", - "Organization": "sdo:Organization", - "name": "sdo:name" - } - }, - "roles": [ - { - "@id": "http://purl.org/spar/scoro/principal-investigator", - "@type": "OntologyAnnotation", - "annotationValue": "principal investigator", - "termSource": "scoro", - "termAccession": "http://purl.org/spar/scoro/principal-investigator", - "@context": { - "sdo": "http://schema.org/", - "OntologyAnnotation": "sdo:DefinedTerm", - "annotationValue": "sdo:name", - "termSource": "sdo:inDefinedTermSet", - "termAccession": "sdo:termCode", - "comments": "sdo:disambiguatingDescription" - } - } - ], - "@context": { - "sdo": "http://schema.org/", - "Person": "sdo:Person", - "orcid": "sdo:identifier", - "firstName": "sdo:givenName", - "lastName": "sdo:familyName", - "midInitials": "sdo:additionalName", - "email": "sdo:email", - "address": "sdo:address", - "phone": "sdo:telephone", - "fax": "sdo:faxNumber", - "comments": "sdo:disambiguatingDescription", - "roles": "sdo:jobTitle", - "affiliation": "sdo:affiliation" - } - }, - { - "@id": "garth@rptu.de", - "@type": "Person", - "firstName": "Christoph", - "lastName": "Garth", - "email": "garth@rptu.de", - "affiliation": { - "@type": "Organization", - "@id": "#Organization_RPTU_University_of_Kaiserslautern", - "name": "RPTU University of Kaiserslautern", - "@context": { - "sdo": "http://schema.org/", - "Organization": "sdo:Organization", - "name": "sdo:name" - } - }, - "roles": [ - { - "@id": "http://purl.org/spar/scoro/principal-investigator", - "@type": "OntologyAnnotation", - "annotationValue": "principal investigator", - "termSource": "scoro", - "termAccession": "http://purl.org/spar/scoro/principal-investigator", - "@context": { - "sdo": "http://schema.org/", - "OntologyAnnotation": "sdo:DefinedTerm", - "annotationValue": "sdo:name", - "termSource": "sdo:inDefinedTermSet", - "termAccession": "sdo:termCode", - "comments": "sdo:disambiguatingDescription" - } - } - ], - "@context": { - "sdo": "http://schema.org/", - "Person": "sdo:Person", - "orcid": "sdo:identifier", - "firstName": "sdo:givenName", - "lastName": "sdo:familyName", - "midInitials": "sdo:additionalName", - "email": "sdo:email", - "address": "sdo:address", - "phone": "sdo:telephone", - "fax": "sdo:faxNumber", - "comments": "sdo:disambiguatingDescription", - "roles": "sdo:jobTitle", - "affiliation": "sdo:affiliation" - } - }, - { - "@id": "maus@nfdi4plants.org", - "@type": "Person", - "orcid": "0000-0002-8241-5300", - "firstName": "Oliver", - "lastName": "Maus", - "email": "maus@nfdi4plants.org", - "address": "RPTU University of Kaiserslautern, Erwin-Schrödinger-Str. 56 , 67663 Kaiserslautern", - "affiliation": { - "@type": "Organization", - "@id": "#Organization_RPTU_University_of_Kaiserslautern", - "name": "RPTU University of Kaiserslautern", - "@context": { - "sdo": "http://schema.org/", - "Organization": "sdo:Organization", - "name": "sdo:name" - } - }, - "roles": [ - { - "@id": "http://purl.org/spar/scoro/research-assistant", - "@type": "OntologyAnnotation", - "annotationValue": "research assistant", - "termSource": "scoro", - "termAccession": "http://purl.org/spar/scoro/research-assistant", - "@context": { - "sdo": "http://schema.org/", - "OntologyAnnotation": "sdo:DefinedTerm", - "annotationValue": "sdo:name", - "termSource": "sdo:inDefinedTermSet", - "termAccession": "sdo:termCode", - "comments": "sdo:disambiguatingDescription" - } - } - ], - "@context": { - "sdo": "http://schema.org/", - "Person": "sdo:Person", - "orcid": "sdo:identifier", - "firstName": "sdo:givenName", - "lastName": "sdo:familyName", - "midInitials": "sdo:additionalName", - "email": "sdo:email", - "address": "sdo:address", - "phone": "sdo:telephone", - "fax": "sdo:faxNumber", - "comments": "sdo:disambiguatingDescription", - "roles": "sdo:jobTitle", - "affiliation": "sdo:affiliation" - } - } - ], - "@context": { - "sdo": "http://schema.org/", - "Investigation": "sdo:Dataset", - "identifier": "sdo:identifier", - "title": "sdo:headline", - "additionalType": "sdo:additionalType", - "description": "sdo:description", - "submissionDate": "sdo:dateCreated", - "publicReleaseDate": "sdo:datePublished", - "publications": "sdo:citation", - "people": "sdo:creator", - "studies": "sdo:hasPart", - "ontologySourceReferences": "sdo:mentions", - "comments": "sdo:comment", - "filename": "sdo:alternateName" - } - }, - "conformsTo": { - "@id": "https://w3id.org/ro/crate/1.1" - }, - "@context": { - "sdo": "http://schema.org/", - "arc": "http://purl.org/nfdi4plants/ontology/", - "CreativeWork": "sdo:CreativeWork", - "about": "sdo:about", - "conformsTo": "sdo:conformsTo" - } -} \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499.fs b/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499.fs new file mode 100644 index 00000000..8360f372 --- /dev/null +++ b/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499.fs @@ -0,0 +1,1697 @@ +module TestObjects.ROCrate.ArcPrototype + +/// https://git.nfdi4plants.org/muehlhaus/ArcPrototype/-/tree/ed12349933062b4440ed2d1e0dc05482853d752d +let ed123499 = """{ + "@context": [ + "https://w3id.org/ro/crate/1.1/context", + { + "Sample": "https://bioschemas.org/Sample", + "additionalProperty": "http://schema.org/additionalProperty", + "intendedUse": "https://bioschemas.org/intendedUse", + "computationalTool": "https://bioschemas.org/computationalTool", + "labEquipment": "https://bioschemas.org/labEquipment", + "reagent": "https://bioschemas.org/reagent", + "LabProtocol": "https://bioschemas.org/LabProtocol", + "executesLabProtocol": "https://bioschemas.org/executesLabProtocol", + "parameterValue": "https://bioschemas.org/parameterValue", + "LabProcess": "https://bioschemas.org/LabProcess" + } + ], + "@graph": [ + { + "@id": "#Organization_RPTU_University_of_Kaiserslautern", + "@type": "Organization", + "name": "RPTU University of Kaiserslautern" + }, + { + "@id": "http://purl.org/spar/scoro/principal-investigator", + "@type": "DefinedTerm", + "name": "principal investigator", + "termCode": "http://purl.org/spar/scoro/principal-investigator" + }, + { + "@id": "https://orcid.org/http://orcid.org/0000-0003-3925-6778", + "@type": "Person", + "givenName": "Timo", + "affiliation": { + "@id": "#Organization_RPTU_University_of_Kaiserslautern" + }, + "email": "timo.muehlhaus@rptu.de", + "familyName": "Mühlhaus", + "jobTitle": { + "@id": "http://purl.org/spar/scoro/principal-investigator" + }, + "address": "RPTU University of Kaiserslautern, Paul-Ehrlich-Str. 23 , 67663 Kaiserslautern", + "telephone": "0 49 (0)631 205 4657" + }, + { + "@id": "#Person_Christoph_Garth", + "@type": "Person", + "givenName": "Christoph", + "affiliation": { + "@id": "#Organization_RPTU_University_of_Kaiserslautern" + }, + "email": "garth@rptu.de", + "familyName": "Garth", + "jobTitle": { + "@id": "http://purl.org/spar/scoro/principal-investigator" + } + }, + { + "@id": "http://purl.org/spar/scoro/research-assistant", + "@type": "DefinedTerm", + "name": "research assistant", + "termCode": "http://purl.org/spar/scoro/research-assistant" + }, + { + "@id": "https://orcid.org/0000-0002-8241-5300", + "@type": "Person", + "givenName": "Oliver", + "affiliation": { + "@id": "#Organization_RPTU_University_of_Kaiserslautern" + }, + "email": "maus@nfdi4plants.org", + "familyName": "Maus", + "jobTitle": { + "@id": "http://purl.org/spar/scoro/research-assistant" + }, + "address": "RPTU University of Kaiserslautern, Erwin-Schrödinger-Str. 56 , 67663 Kaiserslautern" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png", + "@type": "File", + "name": "studies/MaterialPreparation/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png" + }, + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "organism", + "value": "Arabidopsis thaliana", + "propertyID": "https://bioregistry.io/OBI:0100026", + "valueReference": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "columnIndex": "0" + }, + { + "@id": "#CharacteristicValue_biological_replicate_1", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "biological replicate", + "value": "1", + "propertyID": "http://purl.org/nfdi4plants/ontology/dpbo/DPBO_0000042", + "columnIndex": "1" + }, + { + "@id": "#Source_Source1", + "@type": "Sample", + "additionalType": "Source", + "name": "Source1", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_1" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask1", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask1" + }, + { + "@id": "https://bioregistry.io/EFO:0003789", + "@type": "DefinedTerm", + "name": "growth protocol", + "termCode": "https://bioregistry.io/EFO:0003789" + }, + { + "@id": "#Protocol_CellCultivation", + "@type": "LabProtocol", + "intendedUse": { + "@id": "https://bioregistry.io/EFO:0003789" + } + }, + { + "@id": "#Process_CellCultivation_0", + "@type": "LabProcess", + "name": "CellCultivation_0", + "object": { + "@id": "#Source_Source1" + }, + "result": { + "@id": "#Sample_Cultivation_Flask1" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#Source_Source2", + "@type": "Sample", + "additionalType": "Source", + "name": "Source2", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_1" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask2", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask2" + }, + { + "@id": "#Process_CellCultivation_1", + "@type": "LabProcess", + "name": "CellCultivation_1", + "object": { + "@id": "#Source_Source2" + }, + "result": { + "@id": "#Sample_Cultivation_Flask2" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#Source_Source3", + "@type": "Sample", + "additionalType": "Source", + "name": "Source3", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_1" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask3", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask3" + }, + { + "@id": "#Process_CellCultivation_2", + "@type": "LabProcess", + "name": "CellCultivation_2", + "object": { + "@id": "#Source_Source3" + }, + "result": { + "@id": "#Sample_Cultivation_Flask3" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#CharacteristicValue_biological_replicate_2", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "biological replicate", + "value": "2", + "propertyID": "http://purl.org/nfdi4plants/ontology/dpbo/DPBO_0000042", + "columnIndex": "1" + }, + { + "@id": "#Source_Source4", + "@type": "Sample", + "additionalType": "Source", + "name": "Source4", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_2" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask4", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask4" + }, + { + "@id": "#Process_CellCultivation_3", + "@type": "LabProcess", + "name": "CellCultivation_3", + "object": { + "@id": "#Source_Source4" + }, + "result": { + "@id": "#Sample_Cultivation_Flask4" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#Source_Source5", + "@type": "Sample", + "additionalType": "Source", + "name": "Source5", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_2" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask5", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask5" + }, + { + "@id": "#Process_CellCultivation_4", + "@type": "LabProcess", + "name": "CellCultivation_4", + "object": { + "@id": "#Source_Source5" + }, + "result": { + "@id": "#Sample_Cultivation_Flask5" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#Source_Source6", + "@type": "Sample", + "additionalType": "Source", + "name": "Source6", + "additionalProperty": [ + { + "@id": "#CharacteristicValue_organism_Arabidopsis_thaliana" + }, + { + "@id": "#CharacteristicValue_biological_replicate_2" + } + ] + }, + { + "@id": "#Sample_Cultivation_Flask6", + "@type": "Sample", + "additionalType": "Sample", + "name": "Cultivation Flask6" + }, + { + "@id": "#Process_CellCultivation_5", + "@type": "LabProcess", + "name": "CellCultivation_5", + "object": { + "@id": "#Source_Source6" + }, + "result": { + "@id": "#Sample_Cultivation_Flask6" + }, + "executesLabProtocol": { + "@id": "#Protocol_CellCultivation" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_e36ca6b8-19ba-4504-aa82-d4781765873d", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "e36ca6b8-19ba-4504-aa82-d4781765873d", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample1", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample1", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_e36ca6b8-19ba-4504-aa82-d4781765873d" + } + }, + { + "@id": "#Protocol_AccessoryDataRetrieval", + "@type": "LabProtocol" + }, + { + "@id": "#Process_AccessoryDataRetrieval_0", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_0", + "object": { + "@id": "#Sample_Sample1" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_714ca2b7-22b7-4f69-b83d-9165f624da25", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "714ca2b7-22b7-4f69-b83d-9165f624da25", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample2", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample2", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_714ca2b7-22b7-4f69-b83d-9165f624da25" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval_1", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_1", + "object": { + "@id": "#Sample_Sample2" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_66fac760-acc7-4ed4-ba21-2cb67fa36e4d", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "66fac760-acc7-4ed4-ba21-2cb67fa36e4d", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample3", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample3", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_66fac760-acc7-4ed4-ba21-2cb67fa36e4d" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval_2", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_2", + "object": { + "@id": "#Sample_Sample3" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_cba5f40c-fc05-44d6-a589-b0e3dafaeefe", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "cba5f40c-fc05-44d6-a589-b0e3dafaeefe", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample4", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample4", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_cba5f40c-fc05-44d6-a589-b0e3dafaeefe" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval_3", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_3", + "object": { + "@id": "#Sample_Sample4" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_84c37b60-2342-4226-a36c-4b8dfe84ebe9", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "84c37b60-2342-4226-a36c-4b8dfe84ebe9", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample5", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample5", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_84c37b60-2342-4226-a36c-4b8dfe84ebe9" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval_4", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_4", + "object": { + "@id": "#Sample_Sample5" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_208df064-4b1c-4da0-a1f8-6412e1fb2284", + "@type": "PropertyValue", + "additionalType": "CharacteristicValue", + "name": "Performed Procedure Step SOP Instance UID", + "value": "208df064-4b1c-4da0-a1f8-6412e1fb2284", + "propertyID": "https://bioregistry.io/NCIT:C69261", + "columnIndex": "0" + }, + { + "@id": "#Sample_Sample6", + "@type": "Sample", + "additionalType": "Sample", + "name": "Sample6", + "additionalProperty": { + "@id": "#CharacteristicValue_Performed_Procedure_Step_SOP_Instance_UID_208df064-4b1c-4da0-a1f8-6412e1fb2284" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval_5", + "@type": "LabProcess", + "name": "AccessoryDataRetrieval_5", + "object": { + "@id": "#Sample_Sample6" + }, + "result": { + "@id": "studies/MaterialPreparation/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png" + }, + "executesLabProtocol": { + "@id": "#Protocol_AccessoryDataRetrieval" + } + }, + { + "@id": "studies/MaterialPreparation/", + "@type": "Dataset", + "additionalType": "Study", + "identifier": "MaterialPreparation", + "dateModified": "2025-03-04T10:32:21.5629333", + "description": "In this a devised study to have an exemplary experimental material description.", + "hasPart": [ + { + "@id": "studies/MaterialPreparation/resources/Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png" + }, + { + "@id": "studies/MaterialPreparation/resources/Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png" + } + ], + "name": "Prototype for experimental data", + "about": [ + { + "@id": "#Process_CellCultivation_0" + }, + { + "@id": "#Process_CellCultivation_1" + }, + { + "@id": "#Process_CellCultivation_2" + }, + { + "@id": "#Process_CellCultivation_3" + }, + { + "@id": "#Process_CellCultivation_4" + }, + { + "@id": "#Process_CellCultivation_5" + }, + { + "@id": "#Process_AccessoryDataRetrieval_0" + }, + { + "@id": "#Process_AccessoryDataRetrieval_1" + }, + { + "@id": "#Process_AccessoryDataRetrieval_2" + }, + { + "@id": "#Process_AccessoryDataRetrieval_3" + }, + { + "@id": "#Process_AccessoryDataRetrieval_4" + }, + { + "@id": "#Process_AccessoryDataRetrieval_5" + } + ] + }, + { + "@id": "#Source_Input_[MyStudyObject]", + "@type": "Sample", + "additionalType": "Source", + "name": "Input [MyStudyObject]" + }, + { + "@id": "#Sample_MyGel", + "@type": "Sample", + "additionalType": "Sample", + "name": "MyGel" + }, + { + "@id": "#Protocol_experiment2", + "@type": "LabProtocol" + }, + { + "@id": "#ParameterValue_protein_assay_SDS-PAGE", + "@type": "PropertyValue", + "additionalType": "ParameterValue", + "name": "protein assay", + "value": "SDS-PAGE", + "propertyID": "https://bioregistry.io/EFO:0001458", + "valueReference": "https://bioregistry.io/EFO:0010936", + "columnIndex": "0" + }, + { + "@id": "#Process_experiment2", + "@type": "LabProcess", + "name": "experiment2", + "object": { + "@id": "#Source_Input_[MyStudyObject]" + }, + "result": { + "@id": "#Sample_MyGel" + }, + "executesLabProtocol": { + "@id": "#Protocol_experiment2" + }, + "parameterValue": { + "@id": "#ParameterValue_protein_assay_SDS-PAGE" + } + }, + { + "@id": "studies/experiment2/", + "@type": "Dataset", + "additionalType": "Study", + "identifier": "experiment2", + "dateModified": "2025-03-04T10:32:21.5641538", + "hasPart": [], + "about": { + "@id": "#Process_experiment2" + } + }, + { + "@id": "#Person_Oliver_Maus", + "@type": "Person", + "givenName": "Oliver", + "affiliation": { + "@id": "#Organization_RPTU_University_of_Kaiserslautern" + }, + "email": "mailto:maus@nfdi4plants.org", + "familyName": "Maus", + "jobTitle": { + "@id": "http://purl.org/spar/scoro/research-assistant" + }, + "disambiguatingDescription": "Comment {Name = \"Worksheet\"}" + }, + { + "@id": "assays/measurement1/dataset/sample1.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample1.raw" + }, + { + "@id": "assays/measurement1/dataset/sample2.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample2.raw" + }, + { + "@id": "assays/measurement1/dataset/sample3.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample3.raw" + }, + { + "@id": "assays/measurement1/dataset/sample4.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample4.raw" + }, + { + "@id": "assays/measurement1/dataset/sample5.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample5.raw" + }, + { + "@id": "assays/measurement1/dataset/sample6.raw", + "@type": "File", + "name": "assays/measurement1/dataset/sample6.raw" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=1", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=1", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=2", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=2", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=3", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=3", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=4", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=4", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=5", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=5", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=6", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=6", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=7", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=7", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=8", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=8", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=9", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=9", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=10", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=10", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=11", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=11", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=12", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv#col=12", + "encodingFormat": "text/csv", + "usageInfo": "https://datatracker.ietf.org/doc/html/rfc7111" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv", + "@type": "File", + "name": "assays/measurement1/dataset/proteomics_result.csv", + "encodingFormat": "text/csv", + "hasPart": [ + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=1" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=2" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=3" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=4" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=5" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=6" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=7" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=8" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=9" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=10" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=11" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=12" + } + ] + }, + { + "@id": "#Sample_sample_eppi_1", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 1" + }, + { + "@id": "#Component_sonicator_Fisherbrand™_Model_705_Sonic_Dismembrator", + "@type": "PropertyValue", + "additionalType": "Component", + "name": "sonicator", + "value": "Fisherbrand™ Model 705 Sonic Dismembrator", + "propertyID": "https://bioregistry.io/OBI:0400114", + "columnIndex": "1" + }, + { + "@id": "#Component_centrifuge_Eppendorf™_Centrifuge_5420", + "@type": "PropertyValue", + "additionalType": "Component", + "name": "centrifuge", + "value": "Eppendorf™ Centrifuge 5420", + "propertyID": "https://bioregistry.io/OBI:0400106", + "columnIndex": "3" + }, + { + "@id": "#Protocol_Cell_Lysis", + "@type": "LabProtocol", + "labEquipment": [ + { + "@id": "#Component_sonicator_Fisherbrand™_Model_705_Sonic_Dismembrator" + }, + { + "@id": "#Component_centrifuge_Eppendorf™_Centrifuge_5420" + } + ] + }, + { + "@id": "#ParameterValue_cell_lysis_Sonication", + "@type": "PropertyValue", + "additionalType": "ParameterValue", + "name": "cell lysis", + "value": "Sonication", + "propertyID": "https://bioregistry.io/OBI:0302894", + "valueReference": "https://bioregistry.io/NCIT:C81871", + "columnIndex": "0" + }, + { + "@id": "#ParameterValue_centrifugation_10", + "@type": "PropertyValue", + "additionalType": "ParameterValue", + "name": "centrifugation", + "value": "10", + "propertyID": "https://bioregistry.io/OBI:0302886", + "unitCode": "", + "unitText": "g unit", + "columnIndex": "2" + }, + { + "@id": "#Process_Cell_Lysis_0", + "@type": "LabProcess", + "name": "Cell Lysis_0", + "object": { + "@id": "#Sample_Cultivation_Flask1" + }, + "result": { + "@id": "#Sample_sample_eppi_1" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_2", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 2" + }, + { + "@id": "#Process_Cell_Lysis_1", + "@type": "LabProcess", + "name": "Cell Lysis_1", + "object": { + "@id": "#Sample_Cultivation_Flask2" + }, + "result": { + "@id": "#Sample_sample_eppi_2" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_3", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 3" + }, + { + "@id": "#Process_Cell_Lysis_2", + "@type": "LabProcess", + "name": "Cell Lysis_2", + "object": { + "@id": "#Sample_Cultivation_Flask3" + }, + "result": { + "@id": "#Sample_sample_eppi_3" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_4", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 4" + }, + { + "@id": "#Process_Cell_Lysis_3", + "@type": "LabProcess", + "name": "Cell Lysis_3", + "object": { + "@id": "#Sample_Cultivation_Flask4" + }, + "result": { + "@id": "#Sample_sample_eppi_4" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_5", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 5" + }, + { + "@id": "#Process_Cell_Lysis_4", + "@type": "LabProcess", + "name": "Cell Lysis_4", + "object": { + "@id": "#Sample_Cultivation_Flask5" + }, + "result": { + "@id": "#Sample_sample_eppi_5" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_6", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi 6" + }, + { + "@id": "#Process_Cell_Lysis_5", + "@type": "LabProcess", + "name": "Cell Lysis_5", + "object": { + "@id": "#Sample_Cultivation_Flask6" + }, + "result": { + "@id": "#Sample_sample_eppi_6" + }, + "executesLabProtocol": { + "@id": "#Protocol_Cell_Lysis" + }, + "parameterValue": [ + { + "@id": "#ParameterValue_cell_lysis_Sonication" + }, + { + "@id": "#ParameterValue_centrifugation_10" + } + ] + }, + { + "@id": "#Sample_sample_eppi_extracted_1", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 1" + }, + { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction", + "@type": "LabProtocol", + "name": "extractionProtocol.txt" + }, + { + "@id": "#Process_Protein_Extraction_0", + "@type": "LabProcess", + "name": "Protein Extraction_0", + "object": { + "@id": "#Sample_sample_eppi_1" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_1" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_2", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 2" + }, + { + "@id": "#Process_Protein_Extraction_1", + "@type": "LabProcess", + "name": "Protein Extraction_1", + "object": { + "@id": "#Sample_sample_eppi_2" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_2" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_3", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 3" + }, + { + "@id": "#Process_Protein_Extraction_2", + "@type": "LabProcess", + "name": "Protein Extraction_2", + "object": { + "@id": "#Sample_sample_eppi_3" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_3" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_4", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 4" + }, + { + "@id": "#Process_Protein_Extraction_3", + "@type": "LabProcess", + "name": "Protein Extraction_3", + "object": { + "@id": "#Sample_sample_eppi_4" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_4" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_5", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 5" + }, + { + "@id": "#Process_Protein_Extraction_4", + "@type": "LabProcess", + "name": "Protein Extraction_4", + "object": { + "@id": "#Sample_sample_eppi_5" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_5" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_6", + "@type": "Sample", + "additionalType": "Sample", + "name": "sample eppi extracted 6" + }, + { + "@id": "#Process_Protein_Extraction_5", + "@type": "LabProcess", + "name": "Protein Extraction_5", + "object": { + "@id": "#Sample_sample_eppi_6" + }, + "result": { + "@id": "#Sample_sample_eppi_extracted_6" + }, + "executesLabProtocol": { + "@id": "#Protocol_extractionProtocol.txt_Protein_Extraction" + } + }, + { + "@id": "#Component_cleavage_agent_name_Trypsin", + "@type": "PropertyValue", + "additionalType": "Component", + "name": "cleavage agent name", + "value": "Trypsin", + "propertyID": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1001045", + "valueReference": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1001251", + "columnIndex": "0" + }, + { + "@id": "#Component_instrument_model_TripleTOF_5600+", + "@type": "PropertyValue", + "additionalType": "Component", + "name": "instrument model", + "value": "TripleTOF 5600+", + "propertyID": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1000031", + "valueReference": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1002584", + "columnIndex": "1" + }, + { + "@id": "#Protocol_Protein_Measurement", + "@type": "LabProtocol", + "labEquipment": [ + { + "@id": "#Component_cleavage_agent_name_Trypsin" + }, + { + "@id": "#Component_instrument_model_TripleTOF_5600+" + } + ] + }, + { + "@id": "#Process_Protein_Measurement_0", + "@type": "LabProcess", + "name": "Protein Measurement_0", + "object": { + "@id": "#Sample_sample_eppi_extracted_1" + }, + "result": { + "@id": "assays/measurement1/dataset/sample1.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Process_Protein_Measurement_1", + "@type": "LabProcess", + "name": "Protein Measurement_1", + "object": { + "@id": "#Sample_sample_eppi_extracted_2" + }, + "result": { + "@id": "assays/measurement1/dataset/sample2.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Process_Protein_Measurement_2", + "@type": "LabProcess", + "name": "Protein Measurement_2", + "object": { + "@id": "#Sample_sample_eppi_extracted_3" + }, + "result": { + "@id": "assays/measurement1/dataset/sample3.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Process_Protein_Measurement_3", + "@type": "LabProcess", + "name": "Protein Measurement_3", + "object": { + "@id": "#Sample_sample_eppi_extracted_4" + }, + "result": { + "@id": "assays/measurement1/dataset/sample4.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Process_Protein_Measurement_4", + "@type": "LabProcess", + "name": "Protein Measurement_4", + "object": { + "@id": "#Sample_sample_eppi_extracted_5" + }, + "result": { + "@id": "assays/measurement1/dataset/sample5.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Process_Protein_Measurement_5", + "@type": "LabProcess", + "name": "Protein Measurement_5", + "object": { + "@id": "#Sample_sample_eppi_extracted_6" + }, + "result": { + "@id": "assays/measurement1/dataset/sample6.raw" + }, + "executesLabProtocol": { + "@id": "#Protocol_Protein_Measurement" + } + }, + { + "@id": "#Protocol_Computational_Proteome_Analysis", + "@type": "LabProtocol" + }, + { + "@id": "#ParameterValue_software_ProteomIqon", + "@type": "PropertyValue", + "additionalType": "ParameterValue", + "name": "software", + "value": "ProteomIqon", + "propertyID": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1000531", + "columnIndex": "0" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_0", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_0", + "object": { + "@id": "assays/measurement1/dataset/sample1.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=1" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_1", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_1", + "object": { + "@id": "assays/measurement1/dataset/sample1.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=2" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_2", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_2", + "object": { + "@id": "assays/measurement1/dataset/sample2.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=3" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_3", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_3", + "object": { + "@id": "assays/measurement1/dataset/sample2.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=4" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_4", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_4", + "object": { + "@id": "assays/measurement1/dataset/sample3.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=5" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_5", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_5", + "object": { + "@id": "assays/measurement1/dataset/sample3.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=6" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_6", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_6", + "object": { + "@id": "assays/measurement1/dataset/sample4.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=7" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_7", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_7", + "object": { + "@id": "assays/measurement1/dataset/sample4.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=8" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_8", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_8", + "object": { + "@id": "assays/measurement1/dataset/sample5.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=9" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_9", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_9", + "object": { + "@id": "assays/measurement1/dataset/sample5.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=10" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_10", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_10", + "object": { + "@id": "assays/measurement1/dataset/sample6.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=11" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis_11", + "@type": "LabProcess", + "name": "Computational Proteome Analysis_11", + "object": { + "@id": "assays/measurement1/dataset/sample6.raw" + }, + "result": { + "@id": "assays/measurement1/dataset/proteomics_result.csv#col=12" + }, + "executesLabProtocol": { + "@id": "#Protocol_Computational_Proteome_Analysis" + }, + "parameterValue": { + "@id": "#ParameterValue_software_ProteomIqon" + } + }, + { + "@id": "assay/measurement1/", + "@type": "Dataset", + "additionalType": "Assay", + "identifier": "measurement1", + "creator": { + "@id": "#Person_Oliver_Maus" + }, + "hasPart": [ + { + "@id": "assays/measurement1/dataset/sample1.raw" + }, + { + "@id": "assays/measurement1/dataset/sample2.raw" + }, + { + "@id": "assays/measurement1/dataset/sample3.raw" + }, + { + "@id": "assays/measurement1/dataset/sample4.raw" + }, + { + "@id": "assays/measurement1/dataset/sample5.raw" + }, + { + "@id": "assays/measurement1/dataset/sample6.raw" + }, + { + "@id": "assays/measurement1/dataset/proteomics_result.csv" + } + ], + "about": [ + { + "@id": "#Process_Cell_Lysis_0" + }, + { + "@id": "#Process_Cell_Lysis_1" + }, + { + "@id": "#Process_Cell_Lysis_2" + }, + { + "@id": "#Process_Cell_Lysis_3" + }, + { + "@id": "#Process_Cell_Lysis_4" + }, + { + "@id": "#Process_Cell_Lysis_5" + }, + { + "@id": "#Process_Protein_Extraction_0" + }, + { + "@id": "#Process_Protein_Extraction_1" + }, + { + "@id": "#Process_Protein_Extraction_2" + }, + { + "@id": "#Process_Protein_Extraction_3" + }, + { + "@id": "#Process_Protein_Extraction_4" + }, + { + "@id": "#Process_Protein_Extraction_5" + }, + { + "@id": "#Process_Protein_Measurement_0" + }, + { + "@id": "#Process_Protein_Measurement_1" + }, + { + "@id": "#Process_Protein_Measurement_2" + }, + { + "@id": "#Process_Protein_Measurement_3" + }, + { + "@id": "#Process_Protein_Measurement_4" + }, + { + "@id": "#Process_Protein_Measurement_5" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_0" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_1" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_2" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_3" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_4" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_5" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_6" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_7" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_8" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_9" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_10" + }, + { + "@id": "#Process_Computational_Proteome_Analysis_11" + } + ] + }, + { + "@id": "assay/measurement2/", + "@type": "Dataset", + "additionalType": "Assay", + "identifier": "measurement2" + }, + { + "@id": "./", + "@type": "Dataset", + "additionalType": "Investigation", + "identifier": "ArcPrototype", + "creator": [ + { + "@id": "https://orcid.org/http://orcid.org/0000-0003-3925-6778" + }, + { + "@id": "#Person_Christoph_Garth" + }, + { + "@id": "https://orcid.org/0000-0002-8241-5300" + } + ], + "datePublished": "2025-03-04T10:32:21.5643300", + "description": "A prototypic ARC that implements all specification standards accordingly", + "hasPart": [ + { + "@id": "studies/MaterialPreparation/" + }, + { + "@id": "studies/experiment2/" + }, + { + "@id": "assay/measurement1/" + }, + { + "@id": "assay/measurement2/" + } + ], + "name": "ArcPrototype", + "license": "ALL RIGHTS RESERVED BY THE AUTHORS" + }, + { + "@id": "ro-crate-metadata.json", + "@type": "CreativeWork", + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, + "about": { + "@id": "./" + } + } + ] +}""" \ No newline at end of file diff --git a/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499_deprecated.fs b/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499_deprecated.fs new file mode 100644 index 00000000..5c5e7fee --- /dev/null +++ b/tests/TestingUtils/TestObjects.ROCrate/ArcPrototype@ed123499_deprecated.fs @@ -0,0 +1,2956 @@ +module TestObjects.ROCrate.ArcPrototypeDeprecated + +/// https://git.nfdi4plants.org/muehlhaus/ArcPrototype/-/tree/ed12349933062b4440ed2d1e0dc05482853d752d +let ed123499 = """{ + "@type": "CreativeWork", + "@id": "ro-crate-metadata.json", + "about": { + "@id": "./", + "@type": "Investigation", + "additionalType": "Investigation", + "identifier": "ArcPrototype", + "filename": "isa.investigation.xlsx", + "title": "ArcPrototype", + "description": "A prototypic ARC that implements all specification standards accordingly", + "people": [ + { + "@id": "timo.muehlhaus@rptu.de", + "@type": "Person", + "orcid": "http://orcid.org/0000-0003-3925-6778", + "firstName": "Timo", + "lastName": "Mühlhaus", + "email": "timo.muehlhaus@rptu.de", + "phone": "0 49 (0)631 205 4657", + "address": "RPTU University of Kaiserslautern, Paul-Ehrlich-Str. 23 , 67663 Kaiserslautern", + "affiliation": { + "@type": "Organization", + "@id": "#Organization_RPTU_University_of_Kaiserslautern", + "name": "RPTU University of Kaiserslautern", + "@context": { + "sdo": "http://schema.org/", + "Organization": "sdo:Organization", + "name": "sdo:name" + } + }, + "roles": [ + { + "@id": "http://purl.org/spar/scoro/principal-investigator", + "@type": "OntologyAnnotation", + "annotationValue": "principal investigator", + "termSource": "scoro", + "termAccession": "http://purl.org/spar/scoro/principal-investigator", + "@context": { + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Person": "sdo:Person", + "orcid": "sdo:identifier", + "firstName": "sdo:givenName", + "lastName": "sdo:familyName", + "midInitials": "sdo:additionalName", + "email": "sdo:email", + "address": "sdo:address", + "phone": "sdo:telephone", + "fax": "sdo:faxNumber", + "comments": "sdo:disambiguatingDescription", + "roles": "sdo:jobTitle", + "affiliation": "sdo:affiliation" + } + }, + { + "@id": "garth@rptu.de", + "@type": "Person", + "firstName": "Christoph", + "lastName": "Garth", + "email": "garth@rptu.de", + "affiliation": { + "@type": "Organization", + "@id": "#Organization_RPTU_University_of_Kaiserslautern", + "name": "RPTU University of Kaiserslautern", + "@context": { + "sdo": "http://schema.org/", + "Organization": "sdo:Organization", + "name": "sdo:name" + } + }, + "roles": [ + { + "@id": "http://purl.org/spar/scoro/principal-investigator", + "@type": "OntologyAnnotation", + "annotationValue": "principal investigator", + "termSource": "scoro", + "termAccession": "http://purl.org/spar/scoro/principal-investigator", + "@context": { + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Person": "sdo:Person", + "orcid": "sdo:identifier", + "firstName": "sdo:givenName", + "lastName": "sdo:familyName", + "midInitials": "sdo:additionalName", + "email": "sdo:email", + "address": "sdo:address", + "phone": "sdo:telephone", + "fax": "sdo:faxNumber", + "comments": "sdo:disambiguatingDescription", + "roles": "sdo:jobTitle", + "affiliation": "sdo:affiliation" + } + }, + { + "@id": "maus@nfdi4plants.org", + "@type": "Person", + "orcid": "0000-0002-8241-5300", + "firstName": "Oliver", + "lastName": "Maus", + "email": "maus@nfdi4plants.org", + "address": "RPTU University of Kaiserslautern, Erwin-Schrödinger-Str. 56 , 67663 Kaiserslautern", + "affiliation": { + "@type": "Organization", + "@id": "#Organization_RPTU_University_of_Kaiserslautern", + "name": "RPTU University of Kaiserslautern", + "@context": { + "sdo": "http://schema.org/", + "Organization": "sdo:Organization", + "name": "sdo:name" + } + }, + "roles": [ + { + "@id": "http://purl.org/spar/scoro/research-assistant", + "@type": "OntologyAnnotation", + "annotationValue": "research assistant", + "termSource": "scoro", + "termAccession": "http://purl.org/spar/scoro/research-assistant", + "@context": { + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Person": "sdo:Person", + "orcid": "sdo:identifier", + "firstName": "sdo:givenName", + "lastName": "sdo:familyName", + "midInitials": "sdo:additionalName", + "email": "sdo:email", + "address": "sdo:address", + "phone": "sdo:telephone", + "fax": "sdo:faxNumber", + "comments": "sdo:disambiguatingDescription", + "roles": "sdo:jobTitle", + "affiliation": "sdo:affiliation" + } + } + ], + "studies": [ + { + "@id": "#study/MaterialPreparation", + "@type": [ + "Study" + ], + "additionalType": "Study", + "identifier": "MaterialPreparation", + "filename": "studies/MaterialPreparation/isa.study.xlsx", + "title": "Prototype for experimental data", + "description": "In this a devised study to have an exemplary experimental material description.", + "processSequence": [ + { + "@id": "#Process_CellCultivation", + "@type": [ + "Process" + ], + "name": "CellCultivation", + "executesProtocol": { + "@id": "#Protocol_MaterialPreparation_CellCultivation", + "@type": [ + "Protocol" + ], + "protocolType": { + "@id": "https://bioregistry.io/EFO:0003789", + "@type": "OntologyAnnotation", + "annotationValue": "growth protocol", + "termSource": "EFO", + "termAccession": "https://bioregistry.io/EFO:0003789", + "@context": { + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + } + }, + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Protocol": "bio:LabProtocol", + "name": "sdo:name", + "protocolType": "bio:intendedUse", + "description": "sdo:description", + "version": "sdo:version", + "components": "bio:labEquipment", + "reagents": "bio:reagent", + "computationalTools": "bio:computationalTool", + "uri": "sdo:url", + "comments": "sdo:comment" + } + }, + "inputs": [ + { + "@id": "#Source_Source1", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source1", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=1", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "1", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + }, + { + "@id": "#Source_Source2", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source2", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=1", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "1", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + }, + { + "@id": "#Source_Source3", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source3", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=1", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "1", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + }, + { + "@id": "#Source_Source4", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source4", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=2", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "2", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + }, + { + "@id": "#Source_Source5", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source5", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=2", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "2", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + }, + { + "@id": "#Source_Source6", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Source6", + "characteristics": [ + { + "@id": "#MaterialAttributeValue/organism=Arabidopsis thaliana", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "organism", + "categoryCode": "OBI:0100026", + "value": "Arabidopsis thaliana", + "valueCode": "http://purl.obolibrary.org/obo/NCBITaxon_3702", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#MaterialAttributeValue/biological replicate=2", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "biological replicate", + "categoryCode": "DPBO:0000042", + "value": "2", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "#Sample_Cultivation_Flask1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Process_AccessoryDataRetrieval", + "@type": [ + "Process" + ], + "name": "AccessoryDataRetrieval", + "inputs": [ + { + "@id": "#Sample_Sample1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample1", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=e36ca6b8-19ba-4504-aa82-d4781765873d", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "e36ca6b8-19ba-4504-aa82-d4781765873d", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Sample2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample2", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=714ca2b7-22b7-4f69-b83d-9165f624da25", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "714ca2b7-22b7-4f69-b83d-9165f624da25", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Sample3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample3", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=66fac760-acc7-4ed4-ba21-2cb67fa36e4d", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "66fac760-acc7-4ed4-ba21-2cb67fa36e4d", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Sample4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample4", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=cba5f40c-fc05-44d6-a589-b0e3dafaeefe", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "cba5f40c-fc05-44d6-a589-b0e3dafaeefe", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Sample5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample5", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=84c37b60-2342-4226-a36c-4b8dfe84ebe9", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "84c37b60-2342-4226-a36c-4b8dfe84ebe9", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Sample6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Sample6", + "additionalProperties": [ + { + "@id": "#MaterialAttributeValue/Performed Procedure Step SOP Instance UID=208df064-4b1c-4da0-a1f8-6412e1fb2284", + "@type": "PropertyValue", + "additionalType": "MaterialAttributeValue", + "category": "Performed Procedure Step SOP Instance UID", + "categoryCode": "NCIT:C69261", + "value": "208df064-4b1c-4da0-a1f8-6412e1fb2284", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png", + "@type": [ + "Data" + ], + "name": "Sample1_e36ca6b8-19ba-4504-aa82-d4781765873d.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png", + "@type": [ + "Data" + ], + "name": "Sample2_714ca2b7-22b7-4f69-b83d-9165f624da25.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png", + "@type": [ + "Data" + ], + "name": "Sample3_66fac760-acc7-4ed4-ba21-2cb67fa36e4d.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png", + "@type": [ + "Data" + ], + "name": "Sample4_cba5f40c-fc05-44d6-a589-b0e3dafaeefe.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png", + "@type": [ + "Data" + ], + "name": "Sample5_84c37b60-2342-4226-a36c-4b8dfe84ebe9.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png", + "@type": [ + "Data" + ], + "name": "Sample6_208df064-4b1c-4da0-a1f8-6412e1fb2284.png", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "assays": [ + { + "@id": "#assay/measurement1", + "@type": [ + "Assay" + ], + "additionalType": "Assay", + "identifier": "measurement1", + "filename": "assays/measurement1/isa.assay.xlsx", + "performers": [ + { + "@id": "mailto:maus@nfdi4plants.org", + "@type": "Person", + "firstName": "Oliver", + "lastName": "Maus", + "email": "mailto:maus@nfdi4plants.org", + "affiliation": { + "@type": "Organization", + "@id": "#Organization_RPTU_University_of_Kaiserslautern", + "name": "RPTU University of Kaiserslautern", + "@context": { + "sdo": "http://schema.org/", + "Organization": "sdo:Organization", + "name": "sdo:name" + } + }, + "roles": [ + { + "@id": "http://purl.org/spar/scoro/research-assistant", + "@type": "OntologyAnnotation", + "annotationValue": "research assistant", + "termSource": "scoro", + "termAccession": "http://purl.org/spar/scoro/research-assistant", + "@context": { + "sdo": "http://schema.org/", + "OntologyAnnotation": "sdo:DefinedTerm", + "annotationValue": "sdo:name", + "termSource": "sdo:inDefinedTermSet", + "termAccession": "sdo:termCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "comments": [ + "Comment {Name = \"Worksheet\"}" + ], + "@context": { + "sdo": "http://schema.org/", + "Person": "sdo:Person", + "orcid": "sdo:identifier", + "firstName": "sdo:givenName", + "lastName": "sdo:familyName", + "midInitials": "sdo:additionalName", + "email": "sdo:email", + "address": "sdo:address", + "phone": "sdo:telephone", + "fax": "sdo:faxNumber", + "comments": "sdo:disambiguatingDescription", + "roles": "sdo:jobTitle", + "affiliation": "sdo:affiliation" + } + } + ], + "dataFiles": [ + { + "@id": "sample1.raw", + "@type": [ + "Data" + ], + "name": "sample1.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample2.raw", + "@type": [ + "Data" + ], + "name": "sample2.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample3.raw", + "@type": [ + "Data" + ], + "name": "sample3.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample4.raw", + "@type": [ + "Data" + ], + "name": "sample4.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample5.raw", + "@type": [ + "Data" + ], + "name": "sample5.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample6.raw", + "@type": [ + "Data" + ], + "name": "sample6.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample1.raw#", + "@type": [ + "Data" + ], + "name": "sample1.raw#", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=1", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=1", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=2", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=2", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=3", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=3", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=4", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=4", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=5", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=5", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=6", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=6", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=7", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=7", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=8", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=8", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=9", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=9", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=10", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=10", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=11", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=11", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=12", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=12", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + } + ], + "processSequence": [ + { + "@id": "#Process_Cell_Lysis", + "@type": [ + "Process" + ], + "name": "Cell Lysis", + "executesProtocol": { + "@id": "#Protocol_MaterialPreparation_measurement1_Cell_Lysis", + "@type": [ + "Protocol" + ], + "components": [ + { + "@id": "#Component/sonicator=Fisherbrand™ Model 705 Sonic Dismembrator", + "@type": "PropertyValue", + "additionalType": "Component", + "alternateName": "Fisherbrand™ Model 705 Sonic Dismembrator ()", + "category": "sonicator", + "categoryCode": "OBI:0400114", + "value": "Fisherbrand™ Model 705 Sonic Dismembrator", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Component/centrifuge=Eppendorf™ Centrifuge 5420", + "@type": "PropertyValue", + "additionalType": "Component", + "alternateName": "Eppendorf™ Centrifuge 5420 ()", + "category": "centrifuge", + "categoryCode": "OBI:0400106", + "value": "Eppendorf™ Centrifuge 5420", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Protocol": "bio:LabProtocol", + "name": "sdo:name", + "protocolType": "bio:intendedUse", + "description": "sdo:description", + "version": "sdo:version", + "components": "bio:labEquipment", + "reagents": "bio:reagent", + "computationalTools": "bio:computationalTool", + "uri": "sdo:url", + "comments": "sdo:comment" + } + }, + "parameterValues": [ + { + "@id": "#ProcessParameterValue/cell lysis=Sonication", + "@type": "PropertyValue", + "additionalType": "ProcessParameterValue", + "category": "cell lysis", + "categoryCode": "OBI:0302894", + "value": "Sonication", + "valueCode": "https://bioregistry.io/NCIT:C81871", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#ProcessParameterValue/centrifugation=10g unit", + "@type": "PropertyValue", + "additionalType": "ProcessParameterValue", + "category": "centrifugation", + "categoryCode": "OBI:0302886", + "value": 10, + "unit": "g unit", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "inputs": [ + { + "@id": "#Sample_Cultivation_Flask1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_Cultivation_Flask6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "Cultivation Flask6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "#Sample_sample_eppi_1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Process_Protein_Extraction", + "@type": [ + "Process" + ], + "name": "Protein Extraction", + "executesProtocol": { + "@id": "#Protocol_extractionProtocol.txt", + "@type": [ + "Protocol" + ], + "name": "extractionProtocol.txt", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Protocol": "bio:LabProtocol", + "name": "sdo:name", + "protocolType": "bio:intendedUse", + "description": "sdo:description", + "version": "sdo:version", + "components": "bio:labEquipment", + "reagents": "bio:reagent", + "computationalTools": "bio:computationalTool", + "uri": "sdo:url", + "comments": "sdo:comment" + } + }, + "inputs": [ + { + "@id": "#Sample_sample_eppi_1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi 6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "#Sample_sample_eppi_extracted_1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Process_Protein_Measurement", + "@type": [ + "Process" + ], + "name": "Protein Measurement", + "executesProtocol": { + "@id": "#Protocol_MaterialPreparation_measurement1_Protein_Measurement", + "@type": [ + "Protocol" + ], + "components": [ + { + "@id": "#Component/cleavage agent name=Trypsin", + "@type": "PropertyValue", + "additionalType": "Component", + "alternateName": "Trypsin (MS:1001251)", + "category": "cleavage agent name", + "categoryCode": "MS:1001045", + "value": "Trypsin", + "valueCode": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1001251", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Component/instrument model=TripleTOF 5600+", + "@type": "PropertyValue", + "additionalType": "Component", + "alternateName": "TripleTOF 5600+ (MS:1002584)", + "category": "instrument model", + "categoryCode": "MS:1000031", + "value": "TripleTOF 5600+", + "valueCode": "https://www.ebi.ac.uk/ols4/ontologies/ms/classes/http%253A%252F%252Fpurl.obolibrary.org%252Fobo%252FMS_1002584", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Protocol": "bio:LabProtocol", + "name": "sdo:name", + "protocolType": "bio:intendedUse", + "description": "sdo:description", + "version": "sdo:version", + "components": "bio:labEquipment", + "reagents": "bio:reagent", + "computationalTools": "bio:computationalTool", + "uri": "sdo:url", + "comments": "sdo:comment" + } + }, + "inputs": [ + { + "@id": "#Sample_sample_eppi_extracted_1", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 1", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_2", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 2", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_3", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 3", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_4", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 4", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_5", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 5", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + }, + { + "@id": "#Sample_sample_eppi_extracted_6", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "sample eppi extracted 6", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "sample1.raw", + "@type": [ + "Data" + ], + "name": "sample1.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample2.raw", + "@type": [ + "Data" + ], + "name": "sample2.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample3.raw", + "@type": [ + "Data" + ], + "name": "sample3.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample4.raw", + "@type": [ + "Data" + ], + "name": "sample4.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample5.raw", + "@type": [ + "Data" + ], + "name": "sample5.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample6.raw", + "@type": [ + "Data" + ], + "name": "sample6.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + }, + { + "@id": "#Process_Computational_Proteome_Analysis", + "@type": [ + "Process" + ], + "name": "Computational Proteome Analysis", + "parameterValues": [ + { + "@id": "#ProcessParameterValue/software=ProteomIqon", + "@type": "PropertyValue", + "additionalType": "ProcessParameterValue", + "category": "software", + "categoryCode": "MS:1000531", + "value": "ProteomIqon", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "inputs": [ + { + "@id": "sample1.raw#", + "@type": [ + "Data" + ], + "name": "sample1.raw#", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample1.raw", + "@type": [ + "Data" + ], + "name": "sample1.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample2.raw", + "@type": [ + "Data" + ], + "name": "sample2.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample2.raw", + "@type": [ + "Data" + ], + "name": "sample2.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample3.raw", + "@type": [ + "Data" + ], + "name": "sample3.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample3.raw", + "@type": [ + "Data" + ], + "name": "sample3.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample4.raw", + "@type": [ + "Data" + ], + "name": "sample4.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample4.raw", + "@type": [ + "Data" + ], + "name": "sample4.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample5.raw", + "@type": [ + "Data" + ], + "name": "sample5.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample5.raw", + "@type": [ + "Data" + ], + "name": "sample5.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample6.raw", + "@type": [ + "Data" + ], + "name": "sample6.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "sample6.raw", + "@type": [ + "Data" + ], + "name": "sample6.raw", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + } + ], + "outputs": [ + { + "@id": "proteomics_result.csv#col=1", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=1", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=2", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=2", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=3", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=3", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=4", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=4", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=5", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=5", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=6", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=6", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=7", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=7", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=8", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=8", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=9", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=9", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=10", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=10", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=11", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=11", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + }, + { + "@id": "proteomics_result.csv#col=12", + "@type": [ + "Data" + ], + "name": "proteomics_result.csv#col=12", + "type": "Raw Data File", + "@context": { + "sdo": "http://schema.org/", + "Data": "sdo:MediaObject", + "type": "sdo:disambiguatingDescription", + "encodingFormat": "sdo:encodingFormat", + "usageInfo": "sdo:usageInfo", + "name": "sdo:name", + "comments": "sdo:comment" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Assay": "sdo:Dataset", + "identifier": "sdo:identifier", + "additionalType": "sdo:additionalType", + "measurementType": "sdo:variableMeasured", + "technologyType": "sdo:measurementTechnique", + "technologyPlatform": "sdo:measurementMethod", + "dataFiles": "sdo:hasPart", + "performers": "sdo:creator", + "processSequence": "sdo:about", + "comments": "sdo:comment", + "filename": "sdo:url" + } + }, + { + "@id": "#assay/measurement2", + "@type": [ + "Assay" + ], + "additionalType": "Assay", + "identifier": "measurement2", + "filename": "assays/measurement2/isa.assay.xlsx", + "performers": [ + { + "@id": "#EmptyPerson", + "@type": "Person", + "comments": [ + "Comment {Name = \"Worksheet\"}" + ], + "@context": { + "sdo": "http://schema.org/", + "Person": "sdo:Person", + "orcid": "sdo:identifier", + "firstName": "sdo:givenName", + "lastName": "sdo:familyName", + "midInitials": "sdo:additionalName", + "email": "sdo:email", + "address": "sdo:address", + "phone": "sdo:telephone", + "fax": "sdo:faxNumber", + "comments": "sdo:disambiguatingDescription", + "roles": "sdo:jobTitle", + "affiliation": "sdo:affiliation" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Assay": "sdo:Dataset", + "identifier": "sdo:identifier", + "additionalType": "sdo:additionalType", + "measurementType": "sdo:variableMeasured", + "technologyType": "sdo:measurementTechnique", + "technologyPlatform": "sdo:measurementMethod", + "dataFiles": "sdo:hasPart", + "performers": "sdo:creator", + "processSequence": "sdo:about", + "comments": "sdo:comment", + "filename": "sdo:url" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Study": "sdo:Dataset", + "identifier": "sdo:identifier", + "title": "sdo:headline", + "additionalType": "sdo:additionalType", + "description": "sdo:description", + "submissionDate": "sdo:dateCreated", + "publicReleaseDate": "sdo:datePublished", + "publications": "sdo:citation", + "people": "sdo:creator", + "assays": "sdo:hasPart", + "filename": "sdo:alternateName", + "comments": "sdo:comment", + "processSequence": "sdo:about", + "studyDesignDescriptors": "arc:ARC#ARC_00000037" + } + }, + { + "@id": "#study/experiment2", + "@type": [ + "Study" + ], + "additionalType": "Study", + "identifier": "experiment2", + "filename": "studies/experiment2/isa.study.xlsx", + "processSequence": [ + { + "@id": "#Process_experiment2", + "@type": [ + "Process" + ], + "name": "experiment2", + "parameterValues": [ + { + "@id": "#ProcessParameterValue/protein assay=SDS-PAGE", + "@type": "PropertyValue", + "additionalType": "ProcessParameterValue", + "category": "protein assay", + "categoryCode": "EFO:0001458", + "value": "SDS-PAGE", + "valueCode": "https://bioregistry.io/EFO:0010936", + "@context": { + "sdo": "http://schema.org/", + "additionalType": "sdo:additionalType", + "alternateName": "sdo:alternateName", + "measurementMethod": "sdo:measurementMethod", + "description": "sdo:description", + "category": "sdo:name", + "categoryCode": "sdo:propertyID", + "value": "sdo:value", + "valueCode": "sdo:valueReference", + "unit": "sdo:unitText", + "unitCode": "sdo:unitCode", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "inputs": [ + { + "@id": "#Source_Input_[MyStudyObject]", + "@type": [ + "Source" + ], + "additionalType": "Source", + "name": "Input [MyStudyObject]", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Source": "bio:Sample", + "name": "sdo:name", + "characteristics": "bio:additionalProperty" + } + } + ], + "outputs": [ + { + "@id": "#Sample_MyGel", + "@type": [ + "Sample" + ], + "additionalType": "Sample", + "name": "MyGel", + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Sample": "bio:Sample", + "name": "sdo:name", + "additionalProperties": "bio:additionalProperty" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "bio": "https://bioschemas.org/", + "Process": "bio:LabProcess", + "name": "sdo:name", + "executesProtocol": "bio:executesLabProtocol", + "parameterValues": "bio:parameterValue", + "performer": "sdo:agent", + "date": "sdo:endTime", + "inputs": "sdo:object", + "outputs": "sdo:result", + "comments": "sdo:disambiguatingDescription" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Study": "sdo:Dataset", + "identifier": "sdo:identifier", + "title": "sdo:headline", + "additionalType": "sdo:additionalType", + "description": "sdo:description", + "submissionDate": "sdo:dateCreated", + "publicReleaseDate": "sdo:datePublished", + "publications": "sdo:citation", + "people": "sdo:creator", + "assays": "sdo:hasPart", + "filename": "sdo:alternateName", + "comments": "sdo:comment", + "processSequence": "sdo:about", + "studyDesignDescriptors": "arc:ARC#ARC_00000037" + } + } + ], + "@context": { + "sdo": "http://schema.org/", + "Investigation": "sdo:Dataset", + "identifier": "sdo:identifier", + "title": "sdo:headline", + "additionalType": "sdo:additionalType", + "description": "sdo:description", + "submissionDate": "sdo:dateCreated", + "publicReleaseDate": "sdo:datePublished", + "publications": "sdo:citation", + "people": "sdo:creator", + "studies": "sdo:hasPart", + "ontologySourceReferences": "sdo:mentions", + "comments": "sdo:comment", + "filename": "sdo:alternateName" + } + }, + "conformsTo": { + "@id": "https://w3id.org/ro/crate/1.1" + }, + "@context": { + "sdo": "http://schema.org/", + "arc": "http://purl.org/nfdi4plants/ontology/", + "CreativeWork": "sdo:CreativeWork", + "about": "sdo:about", + "conformsTo": "sdo:conformsTo" + } +}""" \ No newline at end of file diff --git a/tests/TestingUtils/TestingUtils.fs b/tests/TestingUtils/TestingUtils.fs index 5ece9115..809ad5e3 100644 --- a/tests/TestingUtils/TestingUtils.fs +++ b/tests/TestingUtils/TestingUtils.fs @@ -198,6 +198,11 @@ module Expect = failwithf "%s. Sequence actual longer than expected, at pos %i found item %O." message i a + let genericSequenceEqual (actual : System.Collections.IEnumerable) (expected : System.Collections.IEnumerable) message = + let actual = [for v in actual do v] + let expected = [for v in expected do v] + sequenceEqual actual expected message + let pathSequenceEqual actual expected message = let actual = actual |> Seq.map trim |> Seq.sort let expected = expected |> Seq.map trim |> Seq.sort diff --git a/tests/TestingUtils/TestingUtils.fsproj b/tests/TestingUtils/TestingUtils.fsproj index ec0911a9..49acbe20 100644 --- a/tests/TestingUtils/TestingUtils.fsproj +++ b/tests/TestingUtils/TestingUtils.fsproj @@ -13,7 +13,8 @@ - + +