code: func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}) *etree.Element {
  	_seenSoFar := make(map[string]struct{})
  	for k, v := range seenSoFar {
  		_seenSoFar[k] = v
  	}
  
  	ne := el.Copy()
  	sort.Sort(etreeutils.SortedAttrs(ne.Attr))
  	if len(ne.Attr) != 0 {
  		for _, attr := range ne.Attr {
  			if attr.Space != nsSpace {
  				continue
  			}
  			key := attr.Space + ":" + attr.Key
  			if _, seen := _seenSoFar[key]; seen {
  				ne.RemoveAttr(attr.Space + ":" + attr.Key)
  			} else {
  				_seenSoFar[key] = struct{}{}
  			}
  		}
  	}
  
  	for i, token := range ne.Child {
  		childElement, ok := token.(*etree.Element)
  		if ok {
  			ne.Child[i] = canonicalPrep(childElement, _seenSoFar)
  		}
  	}
  
  	return ne
  }
docs: // canonicalPrep accepts an *etree.Element and transforms it into one which is ready
  // for serialization into inclusive canonical form. Specifically this
  // entails:
  //
  // 1. Stripping re-declarations of namespaces
  // 2. Sorting attributes into canonical order
  //
  // Inclusive canonicalization does not strip unused namespaces.
  //
  // TODO(russell_h): This is very similar to excCanonicalPrep - perhaps they should
  // be unified into one parameterized function?