func (e ExclusiveCanonicalization) renderAttributes(node *etree.Element, prefixesInScope []string, defaultNS string) (newDefaultNS string, newPrefixesInScope []string) { currentNS := node.SelectAttrValue("xmlns", defaultNS) elementAttributes := []etree.Attr{} nsListToRender := make(map[string]string) attrListToRender := attributes{} // load map with for prefix -> uri lookup for _, attr := range node.Attr { if attr.Space == "xmlns" { e.namespaces[attr.Key] = attr.Value } } // handle the namespace of the node itself if node.Space != "" { if !contains(prefixesInScope, node.Space) { nsListToRender["xmlns:"+node.Space] = e.namespaces[node.Space] prefixesInScope = append(prefixesInScope, node.Space) } } else if defaultNS != currentNS { newDefaultNS = currentNS elementAttributes = append(elementAttributes, etree.Attr{Key: "xmlns", Value: currentNS}) } for _, attr := range node.Attr { // include the namespaces if they are in the inclusiveNamespacePrefixList if attr.Space == "xmlns" { if !contains(prefixesInScope, attr.Key) && contains(e.inclusiveNamespacePrefixList, attr.Key) { nsListToRender["xmlns:"+attr.Key] = attr.Value prefixesInScope = append(prefixesInScope, attr.Key) } } // include namespaces for qualfied attributes if attr.Space != "" && attr.Space != "xmlns" && !contains(prefixesInScope, attr.Space) { nsListToRender["xmlns:"+attr.Space] = e.namespaces[attr.Space] prefixesInScope = append(prefixesInScope, attr.Space) } // inclued all non-namespace attributes if attr.Space != "xmlns" && attr.Key != "xmlns" { attrListToRender = append(attrListToRender, attribute{ prefix: attr.Space, uri: e.namespaces[attr.Space], key: attr.Key, value: attr.Value, }) } } // sort and add the namespace attributes first sortedNSList := getSortedNamespaces(nsListToRender) elementAttributes = append(elementAttributes, sortedNSList...) // then sort and add the non-namespace attributes sortedAttributes := getSortedAttributes(attrListToRender) elementAttributes = append(elementAttributes, sortedAttributes...) // replace the nodes attributes with the sorted copy node.Attr = elementAttributes return currentNS, prefixesInScope }