json-ld / yaml-ld

CG specification for YAML-LD and UCR
https://json-ld.github.io/yaml-ld/spec
Other
19 stars 8 forks source link

use regular expressions to resolve literals; URIs, CURIEs #83

Open VladimirAlexiev opened 1 year ago

VladimirAlexiev commented 1 year ago

As a data architect I want YAML plain values to be recognized by regular expression So that I don't have to explicitly tag them

Examples (Tagging @OR13 and @mgh128 who work with EPCIS data):

"@context": 
  epcis: https://ns.gs1.org/epcis/
issued: 2022-09-01
stringThatOnlyLooksLikeADate: !string 2022-09-01
homepage: https://example.org/foo
stringThatOnlyLooksLikeAUrl: !string https://example.org/foo
urlThatMayBeMisspelled: !anyURI hxxp:\\i-cannot spell,con/my home page
epcis:readPoint: urn:epc:id:sgln:952005385.011.ts4711
epcis:epcList: https://id.gs1.org/01/70614141123451/21/2018

Note: the benefit of datatype xsd:anyURI (tag !anyURI) is that:

We could also use explicit delimiters eg <...> around URNs (URIs, IRIs), which will also enable the use of CURIEs. Eg below each of the props epcis:readPoint, epcis:epcList has 2 identical values (first a full URN, then a CURIE), without having to declare that these are @id properties:

"@context": 
  epcis: https://ns.gs1.org/epcis/
  gtin: https://id.gs1.org/01/
  sgln: "urn:epc:id:sgln:"
epcis:readPoint: 
  - <urn:epc:id:sgln:952005385.011.ts4711>
  - <sgln:952005385.011.ts4711>
epcis:epcList:
  - <https://id.gs1.org/01/70614141123451/21/2018>
  - <gtin:70614141123451/21/2018>

The CURIE spec says

rules for disambiguation in situations where the same string could be interpreted as either a CURIE or an IRI.

I've seen this once in practice:

One way to do this is to require that all CURIEs be expressed as Safe_CURIEs, implying that all unbracketed strings are to be interpreted directly as IRIs.

Safe_CURIEs use [...] delimiters, so we could rewrite the above example as follows:

"@context": 
  epcis: https://ns.gs1.org/epcis/
  gtin: https://id.gs1.org/01/
  sgln: "urn:epc:id:sgln:"
epcis:readPoint: 
  - urn:epc:id:sgln:952005385.011.ts4711
  - [sgln:952005385.011.ts4711]
epcis:epcList:
  - https://id.gs1.org/01/70614141123451/21/2018
  - [gtin:70614141123451/21/2018]

Here we avoid the need for any delimiters in URNs, but the brackets can be confused for "array in flow style":

epcis:epcList: [ https://id.gs1.org/01/70614141123451/21/2018, [gtin:70614141123451/21/2018] ]

We'd need extra spaces around the array brackets, and some damn specialized YAML parsers to grok this.

@ioggstream @gkellogg @anatoly-scherbakov

VladimirAlexiev commented 1 year ago

When a property is @id, its value must be resolved to URN/IRI regardless of any regexes. I should be able to write:

"@context":
  "@sigil": $
  $base: https://friends.com/
  knows: {$type: $id}
$id: valexiev
name: Vladimir
knows: 
  $id: gkellogg
  name: Gregg

Because writing $id: !id valexiev would be "unbearable".

OR13 commented 1 year ago

I like these example... and in this context, the use of CURIEs.

anatoly-scherbakov commented 1 year ago

I feel concerned about both

But the ussue is there.

Perhaps tags like !curie would help?

VladimirAlexiev commented 1 year ago

@gkellogg wrote

YAML tags already use an expression for URIs, although possibly not completely compatible, and with implementation issues for things like '#'.

Can you elaborate? Where?

For dealing with values with the proposed node-tag !id, we would need to rely on a description certainly for distinguishing blank nodes, and allow for relative IRIs and compact IRIs. Probably just defer to the paragraph on Node Objects from JSON-LD to have the same value space and semantics as @id:

If the node object contains the @id key, its value MUST be an IRI reference, or a compact IRI (including blank node identifiers). See § 3.3 Node Identifiers, § 4.1.5 Compact IRIs, and § 4.5.1 Identifying Blank Nodes for further discussion on @id values.

I also like treating URIs and CURIEs in a uniform way (so @anatoly-scherbakov , not using [...] for CURIEs). So @gkellogg is the idea to go like this:

If the context knows that epcis:epcList is an object prop:

epcis:epcList:
  - https://id.gs1.org/01/70614141123451/21/2018
  - gtin:70614141123451/21/2018
# OR
epcis:epcList: [https://id.gs1.org/01/70614141123451/21/2018, gtin:70614141123451/21/2018]

If the context doesn't know, or epcis:epcList is a mixed prop:

epcis:epcList:
  - !id https://id.gs1.org/01/70614141123451/21/2018
  - !id gtin:70614141123451/21/2018
# OR
epcis:epcList: [!id https://id.gs1.org/01/70614141123451/21/2018, !id gtin:70614141123451/21/2018]
ioggstream commented 1 year ago

@VladimirAlexiev I didn't know CURIE.

Probably something like the following can work, but this probably requires a specialized namespace.

foo: !curie [gtin:70614141123451/21/2018]

See security considerations related to tags. They are valid in general and not only in this case. (see https://www.ietf.org/archive/id/draft-ietf-httpapi-yaml-mediatypes-03.html#name-arbitrary-code-execution).

This can be packed with other tag-related features in a specific namespace.

gkellogg commented 1 year ago

@gkellogg wrote

YAML tags already use an expression for URIs, although possibly not completely compatible, and with implementation issues for things like '#'.

Can you elaborate? Where?

The %TAG directive maps a c-tag-handle (such as "!xsd!") to an ns-tag-prefix, which can be an ns-uri-char*. Similarly, a node tag such as !<http://www.w3.org/2001/XMLSchema#dateTime> can be a c-verbatim-tag. Both are effectively URIs, with provisions for escaping characters (such as for IRIs). Therefore, node tags interpreted as Literal datatypes, are already in the form of a URI, and when resolved to the Representation Graph, these should be fully resolved on each node.

For dealing with values with the proposed node-tag !id, we would need to rely on a description certainly for distinguishing blank nodes, and allow for relative IRIs and compact IRIs. Probably just defer to the paragraph on Node Objects from JSON-LD to have the same value space and semantics as @id:

If the node object contains the @id key, its value MUST be an IRI reference, or a compact IRI (including blank node identifiers). See § 3.3 Node Identifiers, § 4.1.5 Compact IRIs, and § 4.5.1 Identifying Blank Nodes for further discussion on @id values.

I also like treating URIs and CURIEs in a uniform way (so @anatoly-scherbakov , not using [...] for CURIEs). So @gkellogg is the idea to go like this:

If the context knows that epcis:epcList is an object prop:

epcis:epcList:
  - https://id.gs1.org/01/70614141123451/21/2018
  - gtin:70614141123451/21/2018
# OR
epcis:epcList: [https://id.gs1.org/01/70614141123451/21/2018, gtin:70614141123451/21/2018]

If the context doesn't know, or epcis:epcList is a mixed prop:

epcis:epcList:
  - !id https://id.gs1.org/01/70614141123451/21/2018
  - !id gtin:70614141123451/21/2018
# OR
epcis:epcList: [!id https://id.gs1.org/01/70614141123451/21/2018, !id gtin:70614141123451/21/2018]

That was basically my thought, although depending on context resolution is a major shortcoming, as I've tried to avoid duplicating the context processing as is done in the JSON-LD Expansion process, so this might be limited to only the top-most context definition without consideration of scoped-contexts. It's definitely a weakness. Relying on specific use of !id would avoid this, but then is little different from simply using {"@id": ...}, in effect. This may not end up being a profitable line of investigation.

Admittedly, my understanding of YAML is pretty basic, so there may be some details of the YAML syntax which are either incompatible, or not properly exploited in these ideas.

ioggstream commented 1 year ago

my understanding of YAML is pretty basic, so there may be some details of the YAML syntax which are either incompatible, or not properly exploited in these ideas

in my experience, it needs quite some time to exploit all the possible ideas. I think that once we "release" the basic profile of yamlld and its media type registration, the json-ld ecosystem will provide enough material to speriment all those not-yet-standardized ideas in the real world.

We will have enough experience to address all the actual issues that will arise to design an extension and identify best practices.

VladimirAlexiev commented 1 year ago

@anatoly-scherbakov I also worry about non-standard YAML parsers (even before this issue), since I haven't seen any parser to properly handle custom tag definitions. As @gkellogg wrote, you can't even use a URI in the tag definition, but have to use the weird tag: scheme.

@gkellogg

YAML tags already use an expression for URIs,

Ok, but you mean resolving tags to URLs. I mean associating regexes with tags so you don't need to use a tag with the value.

CURIEs are a bit of a side topic in this issue:

gkellogg commented 1 year ago

@anatoly-scherbakov I also worry about non-standard YAML parsers (even before this issue), since I haven't seen any parser to properly handle custom tag definitions. As @gkellogg wrote, you can't even use a URI in the tag definition, but have to use the weird tag: scheme.

This was only true for one parser I tried written in Perl, but I've lost the reference now. LibYAML, which is fairly widely used, requires an escape of the '#' character, but otherwise seems to parse ASCII-space URIs.

  • Did we share the "parser testing" matrix here?
  • Do we dare to declare conformance features that would require a good YAML parser supporting all features that we adopt?

Given the varying state of support for the full spec, it would be good do run some cross-platform tests to identify restrictions on using such features.

@gkellogg

YAML tags already use an expression for URIs,

Ok, but you mean resolving tags to URLs. I mean associating regexes with tags so you don't need to use a tag with the value.

In the extended mode, operating on the Representation Graph, we could probably add additional regular expressions to identify types of literals, for example dates, times, dateTimes, and various number formats similar to how specified in Tag Resolution.

Given legal relative forms, doing so for an IRI is challenging, but the forms defined in RFC3986/7 can at least determine if one is considered valid. It may be that it would be too eager, and consider "foo" as being an IRI, as it is a valid path component. Limiting it to full/absolute IRIs would help, but it's still very broad; basically, anything with a ':' could be considered an IRI.

...

VladimirAlexiev commented 1 year ago

Paul Tyson phtyson@sbcglobal.net to public-json-ld@w3.org, Nov 17, 2022: I have a property that can take any type of RDF term as a value.

{
     "@context": {
     "ex": "http://example.org/ns/",
     },
     "ex:thing1": {"ex:foo": 1},
     "ex:thing2": {"ex:foo": "a string"},
     "ex:thing3": {"ex:foo": "http://example.org/yugo"}
     "ex:thing4": {"ex:foo": "2022-11-16T21:04:41"}
}

Is there any way to construct the context to make this come out in RDF like:

_:b0 <http://example.org/ns/thing1> _:b1 .
_:b0 <http://example.org/ns/thing2> _:b2 .
_:b0 <http://example.org/ns/thing3> _:b3 .
_:b0 <http://example.org/ns/thing4> _:b4 .
_:b1 <http://example.org/ns/foo>
"1"^^<http://www.w3.org/2001/XMLSchema#integer> .
_:b2 <http://example.org/ns/foo> "a string" .
_:b3 <http://example.org/ns/foo> <http://example.org/yugo> .
_:b4 <http://example.org/ns/foo>
"2022-11-16T21:04:41"^^<http://www.w3.org/2001/XMLSchema#dateTime> .

Vladimir: There's no way to do this in JSON-LD.

You're asking to leverage regexes to attach appropriate datatypes to literals. I've only seen this in Perl:

We're discussing similar stuff for YAML-LD, see this issue

OR13 commented 1 year ago

I made this a few weekends back:

https://github.com/transmute-industries/jsonld-to-cypher

It has something related internally here:

https://github.com/transmute-industries/jsonld-to-cypher/blob/main/src/utils.js#L30