@@ -288,18 +288,18 @@ func buildXPathStructure(body netconf.Body, xPath string) (netconf.Body, []strin
288288 pathSegments := make ([]string , 0 , len (segments ))
289289
290290 for i , segment := range segments {
291- // Parse segment: element[key='value'][key2='value2'] -> element, map[key:value, key2:value2]
291+ // Parse segment: element[key='value'][key2='value2'] -> element, []KeyValue
292292 elementName , keys := parseXPathSegment (segment )
293293
294294 // Add element name to path (without predicates)
295295 pathSegments = append (pathSegments , elementName )
296296 fullPath := strings .Join (pathSegments [:i + 1 ], "." )
297297
298- // If this segment has keys, set all key values
298+ // If this segment has keys, set all key values in order
299299 if len (keys ) > 0 {
300- for keyName , keyValue := range keys {
301- keyPath := fullPath + "." + keyName
302- body = setWithNamespaces (body , keyPath , keyValue )
300+ for _ , kv := range keys {
301+ keyPath := fullPath + "." + kv . Key
302+ body = setWithNamespaces (body , keyPath , kv . Value )
303303 }
304304 }
305305 }
@@ -318,18 +318,24 @@ func buildXPathStructure(body netconf.Body, xPath string) (netconf.Body, []strin
318318 return body , pathSegments
319319}
320320
321+ // KeyValue represents a key-value pair with preserved order
322+ type KeyValue struct {
323+ Key string
324+ Value string
325+ }
326+
321327// parseXPathSegment parses an XPath segment with single or multiple keys
322328// Supports formats:
323329// - element[key='value']
324330// - element[key1='value1'][key2='value2']
325331// - element[key1='value1' and key2='value2']
326332//
327- // Returns: (elementName, map[keyName]keyValue)
328- func parseXPathSegment (segment string ) (string , map [ string ] string ) {
333+ // Returns: (elementName, []KeyValue) - order is preserved from the XPath
334+ func parseXPathSegment (segment string ) (string , [] KeyValue ) {
329335 // Check for predicate: element[...]
330336 if idx := strings .Index (segment , "[" ); idx != - 1 {
331337 elementName := segment [:idx ]
332- keys := make (map [ string ] string )
338+ keys := make ([] KeyValue , 0 )
333339
334340 // Extract all predicates - handle both [key1='val1'][key2='val2'] and [key1='val1' and key2='val2']
335341 remainingPredicates := segment [idx :]
@@ -346,11 +352,11 @@ func parseXPathSegment(segment string) (string, map[string]string) {
346352 for _ , condition := range conditions {
347353 // Parse each condition: key='value' or key="value"
348354 if eqIdx := strings .Index (condition , "=" ); eqIdx != - 1 {
349- keyName := condition [:eqIdx ]
355+ keyName := strings . TrimSpace ( condition [:eqIdx ])
350356 value := condition [eqIdx + 1 :]
351357 // Remove quotes
352358 keyValue := strings .Trim (value , `'"` )
353- keys [ keyName ] = keyValue
359+ keys = append ( keys , KeyValue { Key : keyName , Value : keyValue })
354360 }
355361 }
356362 }
@@ -508,8 +514,8 @@ func SetRawFromXPath(body netconf.Body, xPath string, value string) netconf.Body
508514 // Build any keys if present
509515 if len (keys ) > 0 {
510516 tempBody := netconf.Body {}
511- for keyName , keyValue := range keys {
512- tempBody = setWithNamespaces (tempBody , keyName , keyValue )
517+ for _ , kv := range keys {
518+ tempBody = setWithNamespaces (tempBody , kv . Key , kv . Value )
513519 }
514520 wrappedContent = "<" + finalElementClean + ">" + tempBody .Res () + value + "</" + finalElementClean + ">"
515521 }
@@ -584,10 +590,9 @@ func GetFromXPath(res xmldot.Result, xPath string) xmldot.Result {
584590 if len (keys ) == 1 {
585591 // Single predicate - use xmldot's native filter syntax
586592 // Also remove namespace prefix from key name
587- for keyName , keyValue := range keys {
588- keyName = removeNamespacePrefix (keyName )
589- pathParts = append (pathParts , elementName + ".#(" + keyName + "==" + keyValue + ")" )
590- }
593+ kv := keys [0 ]
594+ keyName := removeNamespacePrefix (kv .Key )
595+ pathParts = append (pathParts , elementName + ".#(" + keyName + "==" + kv .Value + ")" )
591596 } else {
592597 // No predicates
593598 pathParts = append (pathParts , elementName )
@@ -627,11 +632,11 @@ func GetFromXPath(res xmldot.Result, xPath string) xmldot.Result {
627632 item := xmldot .Get (xml , indexedPath )
628633
629634 allMatch := true
630- for keyName , keyValue := range keys {
635+ for _ , kv := range keys {
631636 // Remove namespace prefix from key name
632- keyName = removeNamespacePrefix (keyName )
637+ keyName : = removeNamespacePrefix (kv . Key )
633638 keyResult := item .Get (keyName )
634- if ! keyResult .Exists () || keyResult .String () != keyValue {
639+ if ! keyResult .Exists () || keyResult .String () != kv . Value {
635640 allMatch = false
636641 break
637642 }
@@ -648,11 +653,11 @@ func GetFromXPath(res xmldot.Result, xPath string) xmldot.Result {
648653 // Single element - check directly
649654 currentResult := xmldot .Get (xml , currentPath )
650655 allMatch := true
651- for keyName , keyValue := range keys {
656+ for _ , kv := range keys {
652657 // Remove namespace prefix from key name
653- keyName = removeNamespacePrefix (keyName )
658+ keyName : = removeNamespacePrefix (kv . Key )
654659 keyResult := currentResult .Get (keyName )
655- if ! keyResult .Exists () || keyResult .String () != keyValue {
660+ if ! keyResult .Exists () || keyResult .String () != kv . Value {
656661 allMatch = false
657662 break
658663 }
@@ -710,12 +715,12 @@ func GetXpathFilter(xPath string) netconf.Filter {
710715
711716 // Reconstruct segment with predicates
712717 if len (keys ) > 0 {
713- // Build predicates
718+ // Build predicates in order
714719 predicates := make ([]string , 0 , len (keys ))
715- for keyName , keyValue := range keys {
720+ for _ , kv := range keys {
716721 // Remove namespace prefix from key name
717- keyName = removeNamespacePrefix (keyName )
718- predicates = append (predicates , fmt .Sprintf ("%s='%s'" , keyName , keyValue ))
722+ keyName : = removeNamespacePrefix (kv . Key )
723+ predicates = append (predicates , fmt .Sprintf ("%s='%s'" , keyName , kv . Value ))
719724 }
720725 // Reconstruct segment with all predicates
721726 reconstructed := elementName
0 commit comments