github.com/aldelo/common@v1.5.1/helper-str.go (about)

     1  package helper
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  import (
    20  	"encoding/base64"
    21  	"encoding/hex"
    22  	"encoding/json"
    23  	"encoding/xml"
    24  	"fmt"
    25  	"github.com/aldelo/common/ascii"
    26  	"html"
    27  	"regexp"
    28  	"strings"
    29  )
    30  
    31  // LenTrim returns length of space trimmed string s
    32  func LenTrim(s string) int {
    33  	return len(strings.TrimSpace(s))
    34  }
    35  
    36  // NextFixedLength calculates the next fixed length total block size,
    37  // for example, if block size is 16, then the total size should be 16, 32, 48 and so on based on data length
    38  func NextFixedLength(data string, blockSize int) int {
    39  	blocks := (len(data) / blockSize) + 1
    40  	blocks = blocks * blockSize
    41  
    42  	return blocks
    43  }
    44  
    45  // Left returns the left side of string indicated by variable l (size of substring)
    46  func Left(s string, l int) string {
    47  	if len(s) <= l {
    48  		return s
    49  	}
    50  
    51  	if l <= 0 {
    52  		return s
    53  	}
    54  
    55  	return s[0:l]
    56  }
    57  
    58  // Right returns the right side of string indicated by variable l (size of substring)
    59  func Right(s string, l int) string {
    60  	if len(s) <= l {
    61  		return s
    62  	}
    63  
    64  	if l <= 0 {
    65  		return s
    66  	}
    67  
    68  	return s[len(s)-l:]
    69  }
    70  
    71  // Mid returns the middle of string indicated by variable start and l positions (size of substring)
    72  func Mid(s string, start int, l int) string {
    73  	if len(s) <= l {
    74  		return s
    75  	}
    76  
    77  	if l <= 0 {
    78  		return s
    79  	}
    80  
    81  	if start > len(s)-1 {
    82  		return s
    83  	}
    84  
    85  	if (len(s) - start) < l {
    86  		return s
    87  	}
    88  
    89  	return s[start : l+start]
    90  }
    91  
    92  // Reverse a string
    93  func Reverse(s string) string {
    94  	chars := []rune(s)
    95  	for i, j := 0, len(chars)-1; i < j; i, j = i+1, j-1 {
    96  		chars[i], chars[j] = chars[j], chars[i]
    97  	}
    98  	return string(chars)
    99  }
   100  
   101  // Replace will replace old char with new char and return the replaced string
   102  func Replace(s string, oldChar string, newChar string) string {
   103  	return strings.Replace(s, oldChar, newChar, -1)
   104  }
   105  
   106  // Trim gets the left and right space trimmed input string s
   107  func Trim(s string) string {
   108  	return strings.TrimSpace(s)
   109  }
   110  
   111  // RightTrimLF will remove linefeed (return char) from the right most char and return result string
   112  func RightTrimLF(s string) string {
   113  	if LenTrim(s) > 0 {
   114  		if Right(s, 2) == "\r\n" {
   115  			return Left(s, len(s)-2)
   116  		}
   117  
   118  		if Right(s, 1) == "\n" {
   119  			return Left(s, len(s)-1)
   120  		}
   121  	}
   122  
   123  	return s
   124  }
   125  
   126  // Padding will pad the data with specified char either to the left or right
   127  func Padding(data string, totalSize int, padRight bool, padChar string) string {
   128  	var result string
   129  	result = data
   130  
   131  	b := []byte(data)
   132  	diff := totalSize - len(b)
   133  
   134  	if diff > 0 {
   135  		var pChar string
   136  
   137  		if len(padChar) == 0 {
   138  			pChar = " "
   139  		} else {
   140  			pChar = string(padChar[0])
   141  		}
   142  
   143  		pad := strings.Repeat(pChar, diff)
   144  
   145  		if padRight {
   146  			result += pad
   147  		} else {
   148  			result = pad + result
   149  		}
   150  	}
   151  
   152  	// return result
   153  	return result
   154  }
   155  
   156  // PadLeft will pad data with space to the left
   157  func PadLeft(data string, totalSize int) string {
   158  	return Padding(data, totalSize, false, " ")
   159  }
   160  
   161  // PadRight will pad data with space to the right
   162  func PadRight(data string, totalSize int) string {
   163  	return Padding(data, totalSize, true, " ")
   164  }
   165  
   166  // PadZero pads zero to the left by default
   167  func PadZero(data string, totalSize int, padRight ...bool) string {
   168  	right := GetFirstBoolOrDefault(false, padRight...)
   169  	return Padding(data, totalSize, right, "0")
   170  }
   171  
   172  // PadX pads X to the left by default
   173  func PadX(data string, totalSize int, padRight ...bool) string {
   174  	right := GetFirstBoolOrDefault(false, padRight...)
   175  	return Padding(data, totalSize, right, "X")
   176  }
   177  
   178  // SplitString will split the source string using delimiter, and return the element indicated by index,
   179  // if nothing is found, blank is returned,
   180  // index = -1 returns last index
   181  func SplitString(source string, delimiter string, index int) string {
   182  	ar := strings.Split(source, delimiter)
   183  
   184  	if len(ar) > 0 {
   185  		if index <= -1 {
   186  			return ar[len(ar)-1]
   187  		} else {
   188  			if len(ar) > index {
   189  				return ar[index]
   190  			} else {
   191  				return ""
   192  			}
   193  		}
   194  	}
   195  
   196  	return ""
   197  }
   198  
   199  // SliceStringToCSVString unboxes slice of string into comma separated string
   200  func SliceStringToCSVString(source []string, spaceAfterComma bool) string {
   201  	output := ""
   202  
   203  	for _, v := range source {
   204  		if LenTrim(output) > 0 {
   205  			output += ","
   206  
   207  			if spaceAfterComma {
   208  				output += " "
   209  			}
   210  		}
   211  
   212  		output += v
   213  	}
   214  
   215  	return output
   216  }
   217  
   218  // ParseKeyValue will parse the input string using specified delimiter (= is default),
   219  // result is set in the key and val fields
   220  func ParseKeyValue(s string, delimiter string, key *string, val *string) error {
   221  	if len(s) <= 2 {
   222  		*key = ""
   223  		*val = ""
   224  		return fmt.Errorf("Source Data Must Exceed 2 Characters")
   225  	}
   226  
   227  	if len(delimiter) == 0 {
   228  		delimiter = "="
   229  	} else {
   230  		delimiter = string(delimiter[0])
   231  	}
   232  
   233  	if strings.Contains(s, delimiter) {
   234  		p := strings.Split(s, delimiter)
   235  
   236  		if len(p) == 2 {
   237  			*key = Trim(p[0])
   238  			*val = Trim(p[1])
   239  			return nil
   240  		}
   241  
   242  		// parts not valid
   243  		*key = ""
   244  		*val = ""
   245  		return fmt.Errorf("Parsed Parts Must Equal 2")
   246  	}
   247  
   248  	// no delimiter found
   249  	*key = ""
   250  	*val = ""
   251  	return fmt.Errorf("Delimiter Not Found in Source Data")
   252  }
   253  
   254  // ExtractNumeric will extract only 0-9 out of string to be returned
   255  func ExtractNumeric(s string) (string, error) {
   256  	exp, err := regexp.Compile("[^0-9]+")
   257  
   258  	if err != nil {
   259  		return "", err
   260  	}
   261  
   262  	return exp.ReplaceAllString(s, ""), nil
   263  }
   264  
   265  // ExtractAlpha will extract A-Z out of string to be returned
   266  func ExtractAlpha(s string) (string, error) {
   267  	exp, err := regexp.Compile("[^A-Za-z]+")
   268  
   269  	if err != nil {
   270  		return "", err
   271  	}
   272  
   273  	return exp.ReplaceAllString(s, ""), nil
   274  }
   275  
   276  // ExtractAlphaNumeric will extract only A-Z, a-z, and 0-9 out of string to be returned
   277  func ExtractAlphaNumeric(s string) (string, error) {
   278  	exp, err := regexp.Compile("[^A-Za-z0-9]+")
   279  
   280  	if err != nil {
   281  		return "", err
   282  	}
   283  
   284  	return exp.ReplaceAllString(s, ""), nil
   285  }
   286  
   287  // ExtractHex will extract only A-F, a-f, and 0-9 out of string to be returned
   288  func ExtractHex(s string) (string, error) {
   289  	exp, err := regexp.Compile("[^A-Fa-f0-9]+")
   290  
   291  	if err != nil {
   292  		return "", err
   293  	}
   294  
   295  	return exp.ReplaceAllString(s, ""), nil
   296  }
   297  
   298  // ExtractAlphaNumericUnderscoreDash will extract only A-Z, a-z, 0-9, _, - out of string to be returned
   299  func ExtractAlphaNumericUnderscoreDash(s string) (string, error) {
   300  	exp, err := regexp.Compile("[^A-Za-z0-9_-]+")
   301  
   302  	if err != nil {
   303  		return "", err
   304  	}
   305  
   306  	return exp.ReplaceAllString(s, ""), nil
   307  }
   308  
   309  // ExtractAlphaNumericPrintableSymbols will extra A-Z, a-z, 0-9, and printable symbols
   310  func ExtractAlphaNumericPrintableSymbols(s string) (string, error) {
   311  	exp, err := regexp.Compile("[^ -~]+")
   312  
   313  	if err != nil {
   314  		return "", err
   315  	}
   316  
   317  	return exp.ReplaceAllString(s, ""), nil
   318  }
   319  
   320  // ExtractByRegex will extract string based on regex expression,
   321  // any regex match will be replaced with blank
   322  func ExtractByRegex(s string, regexStr string) (string, error) {
   323  	exp, err := regexp.Compile(regexStr)
   324  
   325  	if err != nil {
   326  		return "", err
   327  	}
   328  
   329  	return exp.ReplaceAllString(s, ""), nil
   330  }
   331  
   332  // ================================================================================================================
   333  // TYPE CHECK HELPERS
   334  // ================================================================================================================
   335  
   336  // IsAlphanumericOnly checks if the input string is A-Z, a-z, and 0-9 only
   337  func IsAlphanumericOnly(s string) bool {
   338  	exp, err := regexp.Compile("[A-Za-z0-9]+")
   339  
   340  	if err != nil {
   341  		return false
   342  	}
   343  
   344  	if len(exp.ReplaceAllString(s, "")) > 0 {
   345  		// has non alphanumeric
   346  		return false
   347  	} else {
   348  		// alphanumeric only
   349  		return true
   350  	}
   351  }
   352  
   353  // IsAlphanumericAndSpaceOnly checks if the input string is A-Z, a-z, 0-9, and space
   354  func IsAlphanumericAndSpaceOnly(s string) bool {
   355  	exp, err := regexp.Compile("[A-Za-z0-9 ]+")
   356  
   357  	if err != nil {
   358  		return false
   359  	}
   360  
   361  	if len(exp.ReplaceAllString(s, "")) > 0 {
   362  		// has non alphanumeric and space
   363  		return false
   364  	} else {
   365  		// alphanumeric and space only
   366  		return true
   367  	}
   368  }
   369  
   370  // IsBase64Only checks if the input string is a-z, A-Z, 0-9, +, /, =
   371  func IsBase64Only(s string) bool {
   372  	exp, err := regexp.Compile("[A-Za-z0-9+/=]+")
   373  
   374  	if err != nil {
   375  		return false
   376  	}
   377  
   378  	if len(exp.ReplaceAllString(s, "")) > 0 {
   379  		// has non base 64
   380  		return false
   381  	} else {
   382  		// base 64 only
   383  		return true
   384  	}
   385  }
   386  
   387  // IsHexOnly checks if the input string is a-f, A-F, 0-9
   388  func IsHexOnly(s string) bool {
   389  	exp, err := regexp.Compile("[A-Fa-f0-9]+")
   390  
   391  	if err != nil {
   392  		return false
   393  	}
   394  
   395  	if len(exp.ReplaceAllString(s, "")) > 0 {
   396  		// has non hex
   397  		return false
   398  	} else {
   399  		// hex only
   400  		return true
   401  	}
   402  }
   403  
   404  // IsNumericIntOnly checks if the input string is 0-9 only
   405  func IsNumericIntOnly(s string) bool {
   406  	exp, err := regexp.Compile("[0-9]+")
   407  
   408  	if err != nil {
   409  		return false
   410  	}
   411  
   412  	if len(exp.ReplaceAllString(s, "")) > 0 {
   413  		// has non numeric
   414  		return false
   415  	} else {
   416  		// numeric only
   417  		return true
   418  	}
   419  }
   420  
   421  // IsNumericFloat64 checks if string is float
   422  func IsNumericFloat64(s string, positiveOnly bool) bool {
   423  	if LenTrim(s) == 0 {
   424  		return false
   425  	}
   426  
   427  	if f, ok := ParseFloat64(s); !ok {
   428  		return false
   429  	} else {
   430  		if positiveOnly {
   431  			if f < 0 {
   432  				return false
   433  			} else {
   434  				return true
   435  			}
   436  		} else {
   437  			return true
   438  		}
   439  	}
   440  }
   441  
   442  // IsNumericIntAndNegativeSignOnly checks if the input string is 0-9 and possibly with lead negative sign only
   443  func IsNumericIntAndNegativeSignOnly(s string) bool {
   444  	if len(s) == 0 {
   445  		return false
   446  	}
   447  
   448  	if !IsNumericIntOnly(Left(s, 1)) && Left(s, 1) != "-" {
   449  		return false
   450  	}
   451  
   452  	if len(s) > 1 {
   453  		v := Right(s, len(s)-1)
   454  
   455  		if !IsNumericIntOnly(v) {
   456  			return false
   457  		} else {
   458  			return true
   459  		}
   460  	} else {
   461  		if s == "-" {
   462  			return false
   463  		} else {
   464  			return true
   465  		}
   466  	}
   467  }
   468  
   469  // ================================================================================================================
   470  // HEX HELPERS
   471  // ================================================================================================================
   472  
   473  // StringToHex converts string into hex
   474  func StringToHex(data string) string {
   475  	return strings.ToUpper(hex.EncodeToString([]byte(data)))
   476  }
   477  
   478  // ByteToHex converts byte array into hex
   479  func ByteToHex(data []byte) string {
   480  	return strings.ToUpper(hex.EncodeToString(data))
   481  }
   482  
   483  // HexToString converts hex data into string
   484  func HexToString(hexData string) (string, error) {
   485  	data, err := hex.DecodeString(hexData)
   486  
   487  	if err != nil {
   488  		return "", err
   489  	}
   490  
   491  	return string(data), nil
   492  }
   493  
   494  // HexToByte converts hex data into byte array
   495  func HexToByte(hexData string) ([]byte, error) {
   496  	data, err := hex.DecodeString(hexData)
   497  
   498  	if err != nil {
   499  		return []byte{}, err
   500  	}
   501  
   502  	return data, nil
   503  }
   504  
   505  // ================================================================================================================
   506  // BASE64 HELPERS
   507  // ================================================================================================================
   508  
   509  // Base64StdEncode will encode given data into base 64 standard encoded string
   510  func Base64StdEncode(data string) string {
   511  	return base64.StdEncoding.EncodeToString([]byte(data))
   512  }
   513  
   514  // Base64StdDecode will decode given data from base 64 standard encoded string
   515  func Base64StdDecode(data string) (string, error) {
   516  	b, err := base64.StdEncoding.DecodeString(data)
   517  
   518  	if err != nil {
   519  		return "", err
   520  	}
   521  
   522  	return string(b), nil
   523  }
   524  
   525  // Base64UrlEncode will encode given data into base 64 url encoded string
   526  func Base64UrlEncode(data string) string {
   527  	return base64.URLEncoding.EncodeToString([]byte(data))
   528  }
   529  
   530  // Base64UrlDecode will decode given data from base 64 url encoded string
   531  func Base64UrlDecode(data string) (string, error) {
   532  	b, err := base64.URLEncoding.DecodeString(data)
   533  
   534  	if err != nil {
   535  		return "", err
   536  	}
   537  
   538  	return string(b), nil
   539  }
   540  
   541  // ================================================================================================================
   542  // HTML HELPERS
   543  // ================================================================================================================
   544  
   545  // HTMLDecode will unescape html tags and extended tags relevant to our apps
   546  func HTMLDecode(s string) string {
   547  	buf := html.UnescapeString(s)
   548  
   549  	buf = strings.Replace(buf, "&amp;#39;", "'", -1)
   550  	buf = strings.Replace(buf, "&amp;lt;", "<", -1)
   551  	buf = strings.Replace(buf, "&amp;gt;", ">", -1)
   552  	buf = strings.Replace(buf, "&amp;quot;", "\"", -1)
   553  	buf = strings.Replace(buf, "&amp;apos;", "'", -1)
   554  	buf = strings.Replace(buf, "&amp;#169;", "©", -1)
   555  	buf = strings.Replace(buf, "&#39;", "'", -1)
   556  	buf = strings.Replace(buf, "&lt;", "<", -1)
   557  	buf = strings.Replace(buf, "&gt;", ">", -1)
   558  	buf = strings.Replace(buf, "&quot;", "\"", -1)
   559  	buf = strings.Replace(buf, "&apos;", "'", -1)
   560  	buf = strings.Replace(buf, "&#169;", "©", -1)
   561  	buf = strings.Replace(buf, "&lt;FS&gt;", "=", -1)
   562  	buf = strings.Replace(buf, "&lt;GS&gt;", "\n", -1)
   563  
   564  	return buf
   565  }
   566  
   567  // HTMLEncode will escape html tags
   568  func HTMLEncode(s string) string {
   569  	return html.EscapeString(s)
   570  }
   571  
   572  // ================================================================================================================
   573  // XML HELPERS
   574  // ================================================================================================================
   575  
   576  // XMLToEscaped will escape the data whose xml special chars > < & % ' " are escaped into &gt; &lt; &amp; &#37; &apos; &quot;
   577  func XMLToEscaped(data string) string {
   578  	var r string
   579  
   580  	r = strings.Replace(data, "&", "&amp;", -1)
   581  	r = strings.Replace(r, ">", "&gt;", -1)
   582  	r = strings.Replace(r, "<", "&lt;", -1)
   583  	r = strings.Replace(r, "%", "&#37;", -1)
   584  	r = strings.Replace(r, "'", "&apos;", -1)
   585  	r = strings.Replace(r, "\"", "&quot;", -1)
   586  
   587  	return r
   588  }
   589  
   590  // XMLFromEscaped will un-escape the data whose &gt; &lt; &amp; &#37; &apos; &quot; are converted to > < & % ' "
   591  func XMLFromEscaped(data string) string {
   592  	var r string
   593  
   594  	r = strings.Replace(data, "&amp;", "&", -1)
   595  	r = strings.Replace(r, "&gt;", ">", -1)
   596  	r = strings.Replace(r, "&lt;", "<", -1)
   597  	r = strings.Replace(r, "&#37;", "%", -1)
   598  	r = strings.Replace(r, "&apos;", "'", -1)
   599  	r = strings.Replace(r, "&quot;", "\"", -1)
   600  
   601  	return r
   602  }
   603  
   604  // MarshalXMLCompact will accept an input variable, typically struct with xml struct tags, to serialize from object into xml string
   605  //
   606  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   607  //
   608  // special struct field:
   609  //
   610  //	XMLName xml.Name `xml:"ElementName"`
   611  //
   612  // struct xml tags:
   613  //
   614  //	`xml:"AttributeName,attr"` or `xml:",attr"` 		<<< Attribute Instead of Element
   615  //	`xml:"ElementName"`								<<< XML Element Name
   616  //	`xml:"OuterElementName>InnerElementName"` 		<<< Outer XML Grouping By OuterElementName
   617  //	`xml:",cdata"`									<<< <![CDATA[...]]
   618  //	`xml:",innerxml"`								    <<< Write as Inner XML Verbatim and Not Subject to Marshaling
   619  //	`xml:",comment"`									<<< Write as Comment, and Not Contain "--" Within Value
   620  //	`xml:"...,omitempty"`								<<< Omit This Line if Empty Value (false, 0, nil, zero length array)
   621  //	`xml:"-"` <<< Omit From XML Marshal
   622  func MarshalXMLCompact(v interface{}) (string, error) {
   623  	if v == nil {
   624  		return "", fmt.Errorf("Object For XML Marshal Must Not Be Nil")
   625  	}
   626  
   627  	b, err := xml.Marshal(v)
   628  
   629  	if err != nil {
   630  		return "", err
   631  	}
   632  
   633  	return string(b), nil
   634  }
   635  
   636  // MarshalXMLIndent will accept an input variable, typically struct with xml struct tags, to serialize from object into xml string with indented formatting
   637  //
   638  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   639  //
   640  // special struct field:
   641  //
   642  //	XMLName xml.Name `xml:"ElementName"`
   643  //
   644  // struct xml tags:
   645  //
   646  //	`xml:"AttributeName,attr"` or `xml:",attr"` 		<<< Attribute Instead of Element
   647  //	`xml:"ElementName"`								<<< XML Element Name
   648  //	`xml:"OuterElementName>InnerElementName"` 		<<< Outer XML Grouping By OuterElementName
   649  //	`xml:",cdata"`									<<< <![CDATA[...]]
   650  //	`xml:",innerxml"`								    <<< Write as Inner XML Verbatim and Not Subject to Marshaling
   651  //	`xml:",comment"`									<<< Write as Comment, and Not Contain "--" Within Value
   652  //	`xml:"...,omitempty"`								<<< Omit This Line if Empty Value (false, 0, nil, zero length array)
   653  //	`xml:"-"` <<< Omit From XML Marshal
   654  func MarshalXMLIndent(v interface{}) (string, error) {
   655  	if v == nil {
   656  		return "", fmt.Errorf("Object For XML Marshal Must Not Be Nil")
   657  	}
   658  
   659  	b, err := xml.MarshalIndent(v, "", "  ")
   660  
   661  	if err != nil {
   662  		return "", err
   663  	}
   664  
   665  	return string(b), nil
   666  }
   667  
   668  // MarshalXML with option for indent or compact
   669  func MarshalXML(v interface{}, indentXML bool) (string, error) {
   670  	if indentXML {
   671  		return MarshalXMLIndent(v)
   672  	} else {
   673  		return MarshalXMLCompact(v)
   674  	}
   675  }
   676  
   677  // UnmarshalXML will accept input xml data string and deserialize into target object indicated by parameter v
   678  //
   679  // *** PASS PARAMETER AS "&v" IN ORDER TO BE WRITABLE ***
   680  //
   681  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   682  //
   683  // if unmarshal is successful, nil is returned, otherwise error info is returned
   684  func UnmarshalXML(xmlData string, v interface{}) error {
   685  	if LenTrim(xmlData) == 0 {
   686  		return fmt.Errorf("XML Data is Required")
   687  	}
   688  
   689  	return xml.Unmarshal([]byte(xmlData), v)
   690  }
   691  
   692  // ================================================================================================================
   693  // ENCODING JSON HELPERS
   694  // ================================================================================================================
   695  
   696  // JsonToEscaped will escape the data whose json special chars are escaped
   697  func JsonToEscaped(data string) string {
   698  	var r string
   699  
   700  	r = strings.Replace(data, `\`, `\\`, -1)
   701  	r = ascii.EscapeNonPrintable(r)
   702  
   703  	return r
   704  }
   705  
   706  // JsonFromEscaped will unescape the json data that may be special character escaped
   707  func JsonFromEscaped(data string) string {
   708  	var r string
   709  
   710  	r = strings.Replace(data, `\\`, `\`, -1)
   711  	r = ascii.UnescapeNonPrintable(r)
   712  
   713  	if Left(r, 1) == "\"" {
   714  		r = Right(r, len(r)-1)
   715  	}
   716  
   717  	if Right(r, 1) == "\"" {
   718  		r = Left(r, len(r)-1)
   719  	}
   720  
   721  	return r
   722  }
   723  
   724  // MarshalJSONCompact will accept an input variable, typically struct with json struct tags, to serialize from object into json string with compact formatting
   725  //
   726  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   727  //
   728  // struct json tags:
   729  //
   730  //	`json:"ElementName"`								<<< JSON Element Name
   731  //	`json:"...,omitempty"`							<<< Omit This Line if Empty Value (false, 0, nil, zero length array)
   732  //	`json:"-"` <<< Omit From JSON Marshal
   733  func MarshalJSONCompact(v interface{}) (string, error) {
   734  	if v == nil {
   735  		return "", fmt.Errorf("Object For JSON Marshal Must Not Be Nil")
   736  	}
   737  
   738  	b, err := json.Marshal(v)
   739  
   740  	if err != nil {
   741  		return "", err
   742  	}
   743  
   744  	return string(b), nil
   745  }
   746  
   747  // MarshalJSONIndent will accept an input variable, typically struct with json struct tags, to serialize from object into json string with indented formatting
   748  //
   749  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   750  //
   751  // struct json tags:
   752  //
   753  //	`json:"ElementName"`								<<< JSON Element Name
   754  //	`json:"...,omitempty"`							<<< Omit This Line if Empty Value (false, 0, nil, zero length array)
   755  //	`json:"-"` <<< Omit From JSON Marshal
   756  func MarshalJSONIndent(v interface{}) (string, error) {
   757  	if v == nil {
   758  		return "", fmt.Errorf("Object For JSON Marshal Must Not Be Nil")
   759  	}
   760  
   761  	b, err := json.MarshalIndent(v, "", "  ")
   762  
   763  	if err != nil {
   764  		return "", err
   765  	}
   766  
   767  	return string(b), nil
   768  }
   769  
   770  // UnmarshalJSON will accept input json data string and deserialize into target object indicated by parameter v
   771  //
   772  // *** PASS PARAMETER AS "&v" IN ORDER TO BE WRITABLE ***
   773  // *** v interface{} MUST BE initialized first ***
   774  // *** STRUCT FIELDS MUST BE EXPORTED FOR MARSHAL AND UNMARSHAL ***
   775  //
   776  // if unmarshal is successful, nil is returned, otherwise error info is returned
   777  func UnmarshalJSON(jsonData string, v interface{}) error {
   778  	if LenTrim(jsonData) == 0 {
   779  		return fmt.Errorf("JSON Data is Required")
   780  	}
   781  
   782  	return json.Unmarshal([]byte(jsonData), v)
   783  }