github.com/isyscore/isc-gobase@v1.5.3-0.20231218061332-cbc7451899e9/isc/yaml.go (about)

     1  package isc
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"log"
     7  	"reflect"
     8  	"regexp"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"gopkg.in/yaml.v2"
    14  )
    15  
    16  /**
    17   *  1.yaml <---> properties
    18   *  2.yaml <---> json
    19   *  3.yaml <---> map
    20   *  4.yaml <---> list
    21   *  5.yaml <---> kvList
    22   */
    23  
    24  // NewLine 换行符
    25  var NewLine = "\n"
    26  
    27  // IndentBlanks 缩进空格
    28  var IndentBlanks = "  "
    29  
    30  // SignSemicolon 分号连接符
    31  var SignSemicolon = ":"
    32  
    33  // SignEqual 等号连接符
    34  var SignEqual = "="
    35  
    36  // Dot 点
    37  var Dot = "."
    38  
    39  // ArrayBlanks 数组缩进
    40  var ArrayBlanks = "- "
    41  
    42  // YamlNewLineDom yaml的value换行符
    43  var YamlNewLineDom = "|\n"
    44  
    45  var rangePattern = regexp.MustCompile("^(.*)\\[(\\d*)\\]$")
    46  
    47  type TypeEnum int8
    48  
    49  const (
    50  	TeYAML       TypeEnum = 0
    51  	TePROPERTIES TypeEnum = 1
    52  	TeJSON       TypeEnum = 2
    53  	TeSTRING     TypeEnum = 3
    54  )
    55  
    56  type Properties struct {
    57  	Value map[string]string
    58  }
    59  
    60  type StringPair struct {
    61  	Left  string
    62  	Right string
    63  }
    64  
    65  type ConvertError struct {
    66  	errMsg string
    67  }
    68  
    69  func (convertError *ConvertError) Error() string {
    70  	return convertError.errMsg
    71  }
    72  
    73  func IsYaml(content string) bool {
    74  	if !strings.Contains(content, ":") && !strings.Contains(content, "-") {
    75  		return false
    76  	}
    77  
    78  	_, err := YamlToProperties(content)
    79  	if err != nil {
    80  		return false
    81  	}
    82  	return true
    83  }
    84  
    85  func IsProperty(content string) bool {
    86  	if !strings.Contains(content, "=") {
    87  		return false
    88  	}
    89  
    90  	yml, _ := PropertiesToYaml(content)
    91  	_, err := YamlToProperties(yml)
    92  	if err != nil {
    93  		return false
    94  	}
    95  	return true
    96  }
    97  
    98  func IsJson(content string) bool {
    99  	if !strings.HasPrefix(content, "{") && !strings.HasPrefix(content, "[") {
   100  		return false
   101  	}
   102  
   103  	var object any
   104  	err := json.Unmarshal([]byte(content), &object)
   105  	if err != nil {
   106  		return false
   107  	}
   108  	return true
   109  }
   110  
   111  func YamlToProperties(contentOfYaml string) (string, error) {
   112  	// yaml 到 map
   113  	dataMap, err := YamlToMap(contentOfYaml)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  
   118  	return MapToProperties(dataMap)
   119  }
   120  
   121  func YamlToPropertiesWithKey(key string, contentOfYaml string) (string, error) {
   122  	if "" == key {
   123  		return "", &ConvertError{errMsg: "key is nil"}
   124  	}
   125  	if "" == contentOfYaml {
   126  		return key + "=\"\"", nil
   127  	}
   128  	if !strings.Contains(contentOfYaml, ":") && !strings.Contains(contentOfYaml, "-") {
   129  		return "", &ConvertError{errMsg: "content is illegal for yaml"}
   130  	}
   131  
   132  	contentOfYaml = strings.TrimSpace(contentOfYaml)
   133  	if strings.HasPrefix(contentOfYaml, "-") {
   134  		dataMap := make(map[string]any)
   135  		kvList, err := YamlToList(contentOfYaml)
   136  		if err != nil {
   137  			log.Printf("YamlToPropertiesWithKey error: %v, content: %v", err, contentOfYaml)
   138  			return "", err
   139  		}
   140  
   141  		dataMap[key] = kvList
   142  		yamlStr, err := ObjectToYaml(dataMap)
   143  		if err != nil {
   144  			return "", err
   145  		}
   146  		return YamlToProperties(yamlStr)
   147  	}
   148  
   149  	property, err := YamlToProperties(contentOfYaml)
   150  	if err != nil {
   151  		log.Printf("YamlToPropertiesWithKey error: %v, content: %v", err, contentOfYaml)
   152  		return "", err
   153  	}
   154  
   155  	return propertiesAppendPrefixKey(key, property)
   156  }
   157  
   158  func JsonToMap(contentOfJson string) (map[string]any, error) {
   159  	if contentOfJson == "" || (!strings.HasPrefix(contentOfJson, "{") && !strings.HasPrefix(contentOfJson, "[")) {
   160  		return nil, &ChangeError{ErrMsg: "不符合json格式"}
   161  	}
   162  	resultMap := make(map[string]any)
   163  	err := json.Unmarshal([]byte(contentOfJson), &resultMap)
   164  	if err != nil {
   165  		log.Printf("JsonToMap, error: %v, content: %v", err, contentOfJson)
   166  		return nil, err
   167  	}
   168  
   169  	return resultMap, nil
   170  }
   171  
   172  func YamlToMap(contentOfYaml string) (map[string]any, error) {
   173  	resultMap := make(map[string]any)
   174  	err := yaml.Unmarshal([]byte(contentOfYaml), &resultMap)
   175  	if err != nil {
   176  		log.Printf("YamlToMap, error: %v, content: %v", err, contentOfYaml)
   177  		return nil, err
   178  	}
   179  
   180  	return resultMap, nil
   181  }
   182  
   183  func YamlToJson(contentOfYaml string) (string, error) {
   184  	if contentOfYaml != "-" && strings.Contains(contentOfYaml, ":") {
   185  		return "", &ConvertError{errMsg: "the content is invalidate for json"}
   186  	}
   187  
   188  	var data any
   189  	err := yaml.Unmarshal([]byte(contentOfYaml), &data)
   190  	if err != nil {
   191  		log.Printf("YamlToList, error: %v, content: %v", err, contentOfYaml)
   192  		return "", err
   193  	}
   194  
   195  	jsonStr, err := json.Marshal(data)
   196  	if err != nil {
   197  		return "", err
   198  	}
   199  	return string(jsonStr), nil
   200  }
   201  
   202  func YamlToKvList(contentOfYaml string) ([]StringPair, error) {
   203  	if !strings.Contains(contentOfYaml, ":") && !strings.Contains(contentOfYaml, "-") {
   204  		return nil, nil
   205  	}
   206  
   207  	property, err := YamlToProperties(contentOfYaml)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	propertiesLineWordList := GetPropertiesItemLineList(property)
   213  	var pairs []StringPair
   214  	for _, element := range propertiesLineWordList {
   215  		element = strings.TrimSpace(element)
   216  		if "" == element {
   217  			continue
   218  		}
   219  		values := strings.SplitN(element, SignEqual, 2)
   220  		pairs = append(pairs, StringPair{Left: values[0], Right: values[1]})
   221  	}
   222  
   223  	return pairs, nil
   224  }
   225  
   226  func YamlToList(contentOfYaml string) ([]any, error) {
   227  	if !strings.HasPrefix(strings.TrimSpace(contentOfYaml), "-") {
   228  		return []any{}, &ConvertError{errMsg: "the content of yaml not start with '-'"}
   229  	}
   230  	var resultList []any
   231  	err := yaml.Unmarshal([]byte(contentOfYaml), &resultList)
   232  	if err != nil {
   233  		log.Printf("YamlToList, error: %v, content: %v", err, contentOfYaml)
   234  		return nil, err
   235  	}
   236  
   237  	return resultList, nil
   238  }
   239  
   240  func YamlCheck(content string) error {
   241  	if "" == content {
   242  		return &ConvertError{errMsg: "yaml is empty"}
   243  	}
   244  
   245  	if !strings.Contains(content, ":") && !strings.Contains(content, "-") {
   246  		return &ConvertError{errMsg: "yaml content does not contain ':' nor '-'"}
   247  	}
   248  
   249  	if strings.Contains(content, "---\n") {
   250  		return &ConvertError{errMsg: "yaml not support import for content of '---'"}
   251  	}
   252  
   253  	_, err := YamlToProperties(content)
   254  	if err != nil {
   255  		return err
   256  	}
   257  	return nil
   258  }
   259  
   260  func PropertiesToMap(contentOfProperties string) (map[string]any, error) {
   261  	if !strings.Contains(contentOfProperties, "=") {
   262  		return nil, &ConvertError{errMsg: "the content is illegal for properties"}
   263  	}
   264  
   265  	var keyChangeMap = make(map[string]string)
   266  	var resultMap = make(map[string]any)
   267  	propertiesLineWordList := GetPropertiesItemLineList(contentOfProperties)
   268  	for _, line := range propertiesLineWordList {
   269  		line = strings.TrimSpace(line)
   270  		if "" == line {
   271  			continue
   272  		}
   273  
   274  		lineKVs := strings.SplitN(line, "=", 2)
   275  		key := lineKVs[0]
   276  		value := lineKVs[1]
   277  
   278  		if strings.Contains(value, "\n") {
   279  			value = YamlNewLineDom + value
   280  		}
   281  
   282  		if strings.HasPrefix(value, "${") && strings.HasSuffix(value, "}") {
   283  			// 记录两个key,原始key和替代key
   284  			keyChangeMap[key] = value[2:len(value)-1]
   285  			continue
   286  		}
   287  		resultMap[key] = value
   288  	}
   289  
   290  	// 将两个key进行替换
   291  	for keyOriginal, keyNewChange := range keyChangeMap {
   292  		if value, exist := resultMap[keyNewChange]; exist {
   293  			resultMap[keyOriginal] = value
   294  		}
   295  	}
   296  	return resultMap, nil
   297  }
   298  
   299  func propertiesAppendPrefixKey(key string, propertiesContent string) (string, error) {
   300  	itemLines := GetPropertiesItemLineList(propertiesContent)
   301  	var datas []string
   302  	for _, line := range itemLines {
   303  		if !strings.Contains(line, SignEqual) {
   304  			continue
   305  		}
   306  
   307  		kvs := strings.SplitN(line, SignEqual, 2)
   308  		datas = append(datas, key+Dot+kvs[0]+SignEqual+kvs[1])
   309  	}
   310  
   311  	return strings.Join(datas, NewLine), nil
   312  }
   313  
   314  func deepPut(dataMap map[string]any, key string, value any) map[string]any {
   315  	mapValue, exist := dataMap[key]
   316  	if !exist {
   317  		dataMap[key] = value
   318  	} else {
   319  		if reflect.Map == reflect.TypeOf(value).Kind() {
   320  			leftMap := mapValue.(map[string]any)
   321  			rightMap := value.(map[string]any)
   322  
   323  			for rightMapKey := range rightMap {
   324  				leftMap = deepPut(leftMap, rightMapKey, rightMap[rightMapKey])
   325  			}
   326  			dataMap[key] = leftMap
   327  		}
   328  	}
   329  
   330  	return dataMap
   331  }
   332  
   333  func PropertiesToYaml(contentOfProperties string) (string, error) {
   334  	var yamlLineList []string
   335  	var yamlNodes []YamlNode
   336  	propertiesLineWordList := GetPropertiesItemLineList(contentOfProperties)
   337  	for _, line := range propertiesLineWordList {
   338  		line = strings.TrimSpace(line)
   339  		if line != "" {
   340  			// 注释数据不要
   341  			if strings.HasPrefix(line, "#") {
   342  				continue
   343  			}
   344  
   345  			index := strings.Index(line, SignEqual)
   346  			if index > -1 {
   347  				key := line[:index]
   348  				value := line[index+1:]
   349  
   350  				if strings.Contains(value, "\n") {
   351  					value = YamlNewLineDom + value
   352  				}
   353  
   354  				lineWordList := strings.Split(key, ".")
   355  				lineWordList, yamlNodes = wordToNode(lineWordList, yamlNodes, nil, false, -1, appendSpaceForArrayValue(value))
   356  			}
   357  		}
   358  	}
   359  	yamlLineList = formatPropertiesToYaml(yamlLineList, yamlNodes, false, "")
   360  	return strings.Join(yamlLineList, "\n") + "\n", nil
   361  }
   362  
   363  func ObjectToYaml(value any) (string, error) {
   364  	bytes2, err := yaml.Marshal(value)
   365  	if err != nil {
   366  		log.Printf("ObjectToYaml error: %v, content: %v", err, value)
   367  		return "", &ConvertError{errMsg: "ObjectToYaml error"}
   368  	}
   369  	return string(bytes2), nil
   370  }
   371  
   372  // MapToProperties 进行深层嵌套的map数据处理
   373  func MapToProperties(dataMap map[string]any) (string, error) {
   374  	var propertyStrList []string
   375  	for key, value := range dataMap {
   376  		if value == nil {
   377  			continue
   378  		}
   379  		valueKind := reflect.TypeOf(value).Kind()
   380  		switch valueKind {
   381  		case reflect.Map:
   382  			{
   383  				propertyStrList = doMapToProperties(propertyStrList, value, prefixWithDOT("")+key)
   384  			}
   385  		case reflect.Array, reflect.Slice:
   386  			{
   387  				objectValue := reflect.ValueOf(value)
   388  				for index := 0; index < objectValue.Len(); index++ {
   389  					propertyStrList = doMapToProperties(propertyStrList, objectValue.Index(index).Interface(), prefixWithDOT("")+key+"["+strconv.Itoa(index)+"]")
   390  				}
   391  			}
   392  		case reflect.String:
   393  			objectValue := reflect.ValueOf(value)
   394  			objectValueStr := strings.ReplaceAll(objectValue.String(), "\n", "\\\n")
   395  			propertyStrList = append(propertyStrList, prefixWithDOT("")+key+SignEqual+objectValueStr)
   396  		default:
   397  			propertyStrList = append(propertyStrList, prefixWithDOT("")+key+SignEqual+fmt.Sprintf("%v", value))
   398  		}
   399  	}
   400  	resultStr := ""
   401  	for _, propertyStr := range propertyStrList {
   402  		resultStr += propertyStr + "\n"
   403  	}
   404  
   405  	return resultStr, nil
   406  }
   407  
   408  func KvToProperties(key, value string, valueType TypeEnum) (string, error) {
   409  	switch valueType {
   410  	case TeYAML:
   411  		return YamlToPropertiesWithKey(key, value)
   412  	case TeJSON:
   413  		value, err := JsonToYaml(value)
   414  		if err != nil {
   415  			return "", err
   416  		}
   417  		return YamlToPropertiesWithKey(key, value)
   418  	case TePROPERTIES:
   419  		return propertiesAppendPrefixKey(key, value)
   420  	case TeSTRING:
   421  		return key + "=" + appendSpaceForArrayValue(value), nil
   422  	default:
   423  		break
   424  	}
   425  	return "", nil
   426  }
   427  
   428  func JsonToYaml(contentOfJson string) (string, error) {
   429  	if !strings.HasPrefix(contentOfJson, "{") && !strings.HasPrefix(contentOfJson, "[") {
   430  		return "", &ConvertError{errMsg: "content is not json"}
   431  	}
   432  
   433  	if "[]" == contentOfJson {
   434  		return "", nil
   435  	}
   436  
   437  	// go中的json转换不识别"'"字符,因此这里将其转换为"""这种字符
   438  	contentOfJsonTem := strings.ReplaceAll(contentOfJson, "'", "\"")
   439  
   440  	var object any
   441  	err := json.Unmarshal([]byte(contentOfJsonTem), &object)
   442  	if err != nil {
   443  		return "", err
   444  	}
   445  
   446  	return ObjectToYaml(object)
   447  }
   448  
   449  func PropertiesEntityToYaml(properties Properties) (string, error) {
   450  	if properties.Value == nil {
   451  		return "", &ConvertError{"PropertiesEntityToYaml value is empty"}
   452  	}
   453  
   454  	var content = ""
   455  	for key, value := range properties.Value {
   456  		content += key + "=" + value + "\n"
   457  	}
   458  	return PropertiesToYaml(content)
   459  }
   460  
   461  func GetPropertiesItemLineList(content string) []string {
   462  	if "" == content {
   463  		return []string{}
   464  	}
   465  
   466  	lineList := strings.Split(content, NewLine)
   467  	var itemLineList []string
   468  	var stringAppender string
   469  	for _, line := range lineList {
   470  		if strings.HasSuffix(content, "\\") {
   471  			stringAppender += line + "\n"
   472  		} else {
   473  			stringAppender += line
   474  			itemLineList = append(itemLineList, stringAppender)
   475  			stringAppender = ""
   476  		}
   477  	}
   478  	return itemLineList
   479  }
   480  
   481  func formatPropertiesToYaml(yamlLineList []string, yamlNodes []YamlNode, lastNodeArrayFlag bool, blanks string) []string {
   482  	var beforeNodeIndex = -1
   483  	var equalSign string
   484  
   485  	for _, yamlNode := range yamlNodes {
   486  		value := yamlNode.value
   487  
   488  		equalSign = SignSemicolon
   489  		if "" != value {
   490  			equalSign = SignSemicolon + " "
   491  		}
   492  
   493  		yamlNode.resortValue()
   494  
   495  		name := yamlNode.name
   496  		if lastNodeArrayFlag {
   497  			if "" == name {
   498  				yamlLineList = append(yamlLineList, blanks+ArrayBlanks+stringValueWrap(value))
   499  			} else {
   500  				if -1 != beforeNodeIndex && beforeNodeIndex == yamlNode.lastNodeIndex {
   501  					yamlLineList = append(yamlLineList, blanks+IndentBlanks+name+equalSign+stringValueWrap(value))
   502  				} else {
   503  					yamlLineList = append(yamlLineList, blanks+ArrayBlanks+name+equalSign+stringValueWrap(value))
   504  				}
   505  			}
   506  			beforeNodeIndex = yamlNode.lastNodeIndex
   507  		} else {
   508  			yamlLineList = append(yamlLineList, blanks+name+equalSign+stringValueWrap(value))
   509  		}
   510  
   511  		if yamlNode.arrayFlag {
   512  			if lastNodeArrayFlag {
   513  				yamlLineList = formatPropertiesToYaml(yamlLineList, yamlNode.valueList, true, IndentBlanks+IndentBlanks+blanks)
   514  			} else {
   515  				yamlLineList = formatPropertiesToYaml(yamlLineList, yamlNode.valueList, true, IndentBlanks+blanks)
   516  			}
   517  		} else {
   518  			if lastNodeArrayFlag {
   519  				yamlLineList = formatPropertiesToYaml(yamlLineList, yamlNode.children, false, IndentBlanks+IndentBlanks+blanks)
   520  			} else {
   521  				yamlLineList = formatPropertiesToYaml(yamlLineList, yamlNode.children, false, IndentBlanks+blanks)
   522  			}
   523  		}
   524  	}
   525  	return yamlLineList
   526  }
   527  
   528  func wordToNode(lineWordList []string, nodeList []YamlNode, parentNode *YamlNode, lastNodeArrayFlag bool, index int, value string) ([]string, []YamlNode) {
   529  	if len(lineWordList) == 0 {
   530  		if lastNodeArrayFlag {
   531  			node := YamlNode{value: value, lastNodeIndex: -1}
   532  			nodeList = append(nodeList, node)
   533  		}
   534  	} else {
   535  		nodeName := lineWordList[0]
   536  		nodeName, nextIndex := peelArray(nodeName)
   537  
   538  		var node YamlNode
   539  		if nil != parentNode {
   540  			node = YamlNode{name: nodeName, parent: parentNode, lastNodeIndex: index}
   541  		} else {
   542  			node = YamlNode{name: nodeName, lastNodeIndex: index}
   543  		}
   544  		lineWordList = lineWordList[1:]
   545  
   546  		//如果节点下面的子节点数量为0,则为终端节点,也就是赋值节点
   547  		if len(lineWordList) == 0 {
   548  			if -1 == nextIndex {
   549  				node.value = value
   550  			}
   551  		}
   552  
   553  		// nextIndex 不空,表示当前节点为数组,则之后的数据为他的节点数据
   554  		if nextIndex != -1 {
   555  			node.arrayFlag = true
   556  			var hasEqualsName = false
   557  
   558  			//遍历查询节点是否存在
   559  			for innerIndex := range nodeList {
   560  				//如果节点名称已存在,则递归添加剩下的数据节点
   561  				if nodeName == nodeList[innerIndex].name && nodeList[innerIndex].arrayFlag {
   562  					yamlNodeIndex := nodeList[innerIndex].lastNodeIndex
   563  					if -1 == yamlNodeIndex || index == yamlNodeIndex {
   564  						hasEqualsName = true
   565  						lineWordList, nodeList[innerIndex].valueList = wordToNode(lineWordList, nodeList[innerIndex].valueList, node.parent, true, nextIndex, appendSpaceForArrayValue(value))
   566  					}
   567  				}
   568  			}
   569  
   570  			//如果遍历结果为节点名称不存在,则递归添加剩下的数据节点,并把新节点添加到上级yamlTree的子节点中
   571  			if !hasEqualsName {
   572  				lineWordList, node.valueList = wordToNode(lineWordList, node.valueList, node.parent, true, nextIndex, appendSpaceForArrayValue(value))
   573  				nodeList = append(nodeList, node)
   574  			}
   575  		} else {
   576  			var hasEqualsName = false
   577  			for innerIndex := range nodeList {
   578  				if !lastNodeArrayFlag {
   579  					//如果节点名称已存在,则递归添加剩下的数据节点
   580  					if nodeName == nodeList[innerIndex].name {
   581  						hasEqualsName = true
   582  						lineWordList, nodeList[innerIndex].children = wordToNode(lineWordList, nodeList[innerIndex].children, &nodeList[innerIndex], false, nextIndex, appendSpaceForArrayValue(value))
   583  					}
   584  				} else {
   585  					//如果节点名称已存在,则递归添加剩下的数据节点
   586  					if nodeName == nodeList[innerIndex].name {
   587  						yamlNodeIndex := nodeList[innerIndex].lastNodeIndex
   588  						if -1 == yamlNodeIndex || index == yamlNodeIndex {
   589  							hasEqualsName = true
   590  							lineWordList, nodeList[innerIndex].children = wordToNode(lineWordList, nodeList[innerIndex].children, &nodeList[innerIndex], true, nextIndex, appendSpaceForArrayValue(value))
   591  						}
   592  					}
   593  				}
   594  			}
   595  
   596  			//如果遍历结果为节点名称不存在,则递归添加剩下的数据节点,并把新节点添加到上级yamlTree的子节点中
   597  			if !hasEqualsName {
   598  				lineWordList, node.children = wordToNode(lineWordList, node.children, &node, false, nextIndex, appendSpaceForArrayValue(value))
   599  				nodeList = append(nodeList, node)
   600  			}
   601  		}
   602  	}
   603  	return lineWordList, nodeList
   604  }
   605  
   606  func doMapToProperties(propertyStrList []string, value any, prefix string) []string {
   607  	if value == nil {
   608  		return propertyStrList
   609  	}
   610  	valueKind := reflect.TypeOf(value).Kind()
   611  	switch valueKind {
   612  	case reflect.Map:
   613  		{
   614  			// map结构
   615  			if reflect.ValueOf(value).Len() == 0 {
   616  				return propertyStrList
   617  			}
   618  
   619  			for mapR := reflect.ValueOf(value).MapRange(); mapR.Next(); {
   620  				mapKey := mapR.Key().Interface()
   621  				mapValue := mapR.Value().Interface()
   622  				propertyStrList = doMapToProperties(propertyStrList, mapValue, prefixWithDOT(prefix)+fmt.Sprintf("%v", mapKey))
   623  			}
   624  		}
   625  	case reflect.Array, reflect.Slice:
   626  		{
   627  			objectValue := reflect.ValueOf(value)
   628  			for index := 0; index < objectValue.Len(); index++ {
   629  				propertyStrList = doMapToProperties(propertyStrList, objectValue.Index(index).Interface(), prefix+"["+strconv.Itoa(index)+"]")
   630  			}
   631  		}
   632  	case reflect.String:
   633  		objectValue := reflect.ValueOf(value)
   634  		objectValueStr := strings.ReplaceAll(objectValue.String(), "\n", "\\\n")
   635  		propertyStrList = append(propertyStrList, prefix+SignEqual+objectValueStr)
   636  	default:
   637  		objectValue := fmt.Sprintf("%v", reflect.ValueOf(value))
   638  		propertyStrList = append(propertyStrList, prefix+SignEqual+objectValue)
   639  	}
   640  	return propertyStrList
   641  }
   642  
   643  func prefixWithDOT(prefix string) string {
   644  	if "" == prefix {
   645  		return ""
   646  	}
   647  	return prefix + "."
   648  }
   649  
   650  func peelArray(nodeName string) (string, int) {
   651  	var index = -1
   652  	var name = nodeName
   653  	var err error
   654  
   655  	subData := rangePattern.FindAllStringSubmatch(nodeName, -1)
   656  	if len(subData) > 0 {
   657  		name = subData[0][1]
   658  		indexStr := subData[0][2]
   659  		if "" != indexStr {
   660  			index, err = strconv.Atoi(indexStr)
   661  			if err != nil {
   662  				log.Printf("解析错误, nodeName=" + nodeName)
   663  				return "", -1
   664  			}
   665  		}
   666  	}
   667  	return name, index
   668  }
   669  
   670  //
   671  // 将yaml对应的这种value进行添加前缀空格,其中value为key1对应的value
   672  // test:
   673  //   key1: |
   674  //     value1
   675  //     value2
   676  //     value3
   677  // 对应的值
   678  // {@code
   679  // |
   680  // value1
   681  // value2
   682  // value3
   683  // }
   684  //
   685  // @param Value 待转换的值比如{@code
   686  //              test:
   687  //              key1: |
   688  //              value1
   689  //              value2
   690  //              value3
   691  //              }
   692  // @return 添加前缀空格之后的处理
   693  // {@code
   694  // |
   695  // value1
   696  // value2
   697  // value3
   698  // }
   699  //
   700  func appendSpaceForArrayValue(value string) string {
   701  	if !strings.HasPrefix(value, YamlNewLineDom) {
   702  		return value
   703  	}
   704  
   705  	value = value[len(YamlNewLineDom):]
   706  	valueTems := strings.Split(value, "\\n")
   707  
   708  	var strs []string
   709  	for _, element := range valueTems {
   710  		tem := element
   711  		if strings.HasSuffix(element, "\\") {
   712  			tem = element[:len(element)-1]
   713  		}
   714  		strs = append(strs, IndentBlanks+tem)
   715  	}
   716  	return YamlNewLineDom + strings.Join(strs, "\n")
   717  }
   718  
   719  func stringValueWrap(value string) string {
   720  	if "" == value {
   721  		return ""
   722  	}
   723  	// 对数组的数据进行特殊处理
   724  	if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
   725  		return "'" + value + "'"
   726  	}
   727  	return value
   728  }
   729  
   730  type YamlNode struct {
   731  
   732  	// 父节点
   733  	parent *YamlNode
   734  
   735  	// 只有parent为null时候,该值才可能有值
   736  	projectRemark string
   737  
   738  	// name
   739  	name string
   740  
   741  	// value
   742  	value string
   743  
   744  	// 子节点
   745  	children []YamlNode
   746  
   747  	// 数组标示
   748  	arrayFlag bool
   749  
   750  	// 存储的数组中的前一个节点的下标
   751  	lastNodeIndex int
   752  
   753  	// 只有数组标示为true,下面的value才有值
   754  	valueList []YamlNode
   755  }
   756  
   757  func (yamlNode *YamlNode) resortValue() {
   758  	if !yamlNode.arrayFlag || len(yamlNode.valueList) == 0 {
   759  		return
   760  	}
   761  
   762  	sort.Slice(yamlNode.valueList, func(i, j int) bool {
   763  		a := yamlNode.valueList[i]
   764  		b := yamlNode.valueList[j]
   765  
   766  		if -1 == a.lastNodeIndex || -1 == b.lastNodeIndex {
   767  			return false
   768  		}
   769  		return a.lastNodeIndex < b.lastNodeIndex
   770  	})
   771  
   772  	for _, node := range yamlNode.valueList {
   773  		node.resortValue()
   774  	}
   775  }