MatchesXsAnyUri🔗
Check that
text conforms to the pattern of an xs:anyURI.
See: https://www.w3.org/TR/xmlschema-2/#anyURI and https://datatracker.ietf.org/doc/html/rfc2396 and https://datatracker.ietf.org/doc/html/rfc2732
Note, that version 1.0 of the XSD specification defines xs:anyURI as
"defined by RFC 2396, as amended by RFC 2732". Therefore, we use a
pattern here that implements the amendments of RFC 2732. This should not
be confused with matches_RFC_2396, which does not include those
amendments and is used in different parts of the specification.
Code
alphanum = "[a-zA-Z0-9]"
mark = "[\\-_.!~*'()]"
unreserved = f"({alphanum}|{mark})"
hex = "([0-9]|[aA]|[bB]|[cC]|[dD]|[eE]|[fF]|[aA]|[bB]|[cC]|[dD]|[eE]|[fF])"
escaped = f"%{hex}{hex}"
pchar = f"({unreserved}|{escaped}|[:@&=+$,])"
param = f"({pchar})*"
segment = f"({pchar})*(;{param})*"
path_segments = f"{segment}(/{segment})*"
abs_path = f"/{path_segments}"
scheme = "[a-zA-Z][a-zA-Z0-9+\\-.]*"
userinfo = f"({unreserved}|{escaped}|[;:&=+$,])*"
domainlabel = f"({alphanum}|{alphanum}({alphanum}|-)*{alphanum})"
toplabel = f"([a-zA-Z]|[a-zA-Z]({alphanum}|-)*{alphanum})"
hostname = f"({domainlabel}\\.)*{toplabel}(\\.)?"
ipv4address = "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"
hex4 = "[0-9A-Fa-f]{1,4}"
hexseq = f"{hex4}(:{hex4})*"
hexpart = f"({hexseq}|{hexseq}::({hexseq})?|::({hexseq})?)"
ipv6address = f"{hexpart}(:{ipv4address})?"
ipv6reference = f"\\[{ipv6address}\\]"
host = f"({hostname}|{ipv4address}|{ipv6reference})"
port = "[0-9]*"
hostport = f"{host}(:{port})?"
server = f"(({userinfo}@)?{hostport})?"
reg_name = f"({unreserved}|{escaped}|[$,;:@&=+])+"
authority = f"({server}|{reg_name})"
net_path = f"//{authority}({abs_path})?"
reserved = "[;/?:@&=+$,\\[\\]]"
uric = f"({reserved}|{unreserved}|{escaped})"
query = f"({uric})*"
hier_part = f"({net_path}|{abs_path})(\\?{query})?"
uric_no_slash = f"({unreserved}|{escaped}|[;?:@&=+$,])"
opaque_part = f"{uric_no_slash}({uric})*"
absoluteuri = f"{scheme}:({hier_part}|{opaque_part})"
fragment = f"({uric})*"
rel_segment = f"({unreserved}|{escaped}|[;@&=+$,])+"
rel_path = f"{rel_segment}({abs_path})?"
relativeuri = f"({net_path}|{abs_path}|{rel_path})(\\?{query})?"
uri_reference = f"^({absoluteuri}|{relativeuri})?(\\#{fragment})?$"
return match(uri_reference, text) is not None