urn.go (2081B)
1 package urn 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 ) 8 9 const errInvalidURN = "invalid URN: %s" 10 11 // URN represents an Uniform Resource Name. 12 // 13 // The general form represented is: 14 // 15 // urn:<id>:<ss> 16 // 17 // Details at https://tools.ietf.org/html/rfc2141. 18 type URN struct { 19 prefix string // Static prefix. Equal to "urn" when empty. 20 ID string // Namespace identifier 21 SS string // Namespace specific string 22 norm string // Normalized namespace specific string 23 } 24 25 // Normalize turns the receiving URN into its norm version. 26 // 27 // Which means: lowercase prefix, lowercase namespace identifier, and immutate namespace specific string chars (except <hex> tokens which are lowercased). 28 func (u *URN) Normalize() *URN { 29 return &URN{ 30 prefix: "urn", 31 ID: strings.ToLower(u.ID), 32 SS: u.norm, 33 } 34 } 35 36 // Equal checks the lexical equivalence of the current URN with another one. 37 func (u *URN) Equal(x *URN) bool { 38 return *u.Normalize() == *x.Normalize() 39 } 40 41 // String reassembles the URN into a valid URN string. 42 // 43 // This requires both ID and SS fields to be non-empty. 44 // Otherwise it returns an empty string. 45 // 46 // Default URN prefix is "urn". 47 func (u *URN) String() string { 48 var res string 49 if u.ID != "" && u.SS != "" { 50 if u.prefix == "" { 51 res += "urn" 52 } 53 res += u.prefix + ":" + u.ID + ":" + u.SS 54 } 55 56 return res 57 } 58 59 // Parse is responsible to create an URN instance from a byte array matching the correct URN syntax. 60 func Parse(u []byte) (*URN, bool) { 61 urn, err := NewMachine().Parse(u) 62 if err != nil { 63 return nil, false 64 } 65 66 return urn, true 67 } 68 69 // MarshalJSON marshals the URN to JSON string form (e.g. `"urn:oid:1.2.3.4"`). 70 func (u URN) MarshalJSON() ([]byte, error) { 71 return json.Marshal(u.String()) 72 } 73 74 // MarshalJSON unmarshals a URN from JSON string form (e.g. `"urn:oid:1.2.3.4"`). 75 func (u *URN) UnmarshalJSON(bytes []byte) error { 76 var str string 77 if err := json.Unmarshal(bytes, &str); err != nil { 78 return err 79 } 80 if value, ok := Parse([]byte(str)); !ok { 81 return fmt.Errorf(errInvalidURN, str) 82 } else { 83 *u = *value 84 } 85 return nil 86 }