gt:         localName = ISO9075.decode(localName);
context: /*
   * #%L
   * Alfresco Repository
   * %%
   * Copyright (C) 2005 - 2016 Alfresco Software Limited
   * %%
   * This file is part of the Alfresco software. 
   * If the software was purchased under a paid Alfresco license, the terms of 
   * the paid license agreement will prevail.  Otherwise, the software is 
   * provided under the following open source license terms:
   * 
   * Alfresco is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   * 
   * Alfresco is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   * 
   * You should have received a copy of the GNU Lesser General Public License
   * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
   * #L%
   */
  package org.alfresco.repo.search;
  
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import org.alfresco.model.ContentModel;
  import org.alfresco.service.cmr.dictionary.DictionaryService;
  import org.alfresco.service.cmr.repository.ChildAssociationRef;
  import org.alfresco.service.cmr.repository.NodeRef;
  import org.alfresco.service.cmr.repository.NodeService;
  import org.alfresco.service.cmr.repository.StoreRef;
  import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
  import org.alfresco.service.cmr.search.SearchParameters;
  import org.alfresco.service.cmr.search.SearchService;
  import org.alfresco.service.namespace.NamespacePrefixResolver;
  import org.alfresco.service.namespace.QName;
  import org.alfresco.service.namespace.QNamePattern;
  import org.alfresco.service.namespace.RegexQNamePattern;
  import org.alfresco.util.EqualsHelper;
  import org.alfresco.util.ISO9075;
  import org.jaxen.DefaultNavigator;
  import org.jaxen.JaxenException;
  import org.jaxen.NamedAccessNavigator;
  import org.jaxen.UnsupportedAxisException;
  import org.jaxen.XPath;
  
  /**
   * An implementation of the Jaxen xpath against the node service API
   * 
   * This means any node service can do xpath style navigation. Given any context
   * node we can navigate between nodes using xpath.
   * 
   * This allows simple path navigation and much more.
   * 
   * @author Andy Hind
   * 
   */
  public class DocumentNavigator extends DefaultNavigator implements NamedAccessNavigator
  {
      private static final long serialVersionUID = 3618984485740165427L;
  
      private DictionaryService dictionaryService;
  
      private NodeService nodeService;
  
      private SearchService searchService;
  
      private NamespacePrefixResolver nspr;
  
      // Support classes to encapsulate stuff more akin to xml
  
      public class Property
      {
          public final QName qname;
  
          public final Serializable value;
  
          public final NodeRef parent;
  
          public Property(QName qname, Serializable value, NodeRef parent)
          {
              this.qname = qname;
              this.value = value;
              this.parent = parent;
          }
      }
  
     
      public class Namespace
      {
          public final String prefix;
  
          public final String uri;
  
          public Namespace(String prefix, String uri)
          {
              this.prefix = prefix;
              this.uri = uri;
          }
      }
      
      private boolean followAllParentLinks;
      
      /**
       * @deprecated useJCRRootNode parameter is now obsolete.
       */
      public DocumentNavigator(DictionaryService dictionaryService, NodeService nodeService, SearchService searchService,
              NamespacePrefixResolver nspr, boolean followAllParentLinks, boolean useJCRRootNode)
      {
          this(dictionaryService, nodeService, searchService, nspr, followAllParentLinks);
      }
      
      /**
       * @param dictionaryService
       *            used to resolve the <b>subtypeOf</b> function and other
       *            type-related functions
       * @param nodeService
       *            the <tt>NodeService</tt> against which to execute
       * @param searchService
       *            the service that helps resolve functions such as <b>like</b>
       *            and <b>contains</b>
       * @param nspr
       *            resolves namespaces in the xpath
       * @param followAllParentLinks
       *            true if the XPath should traverse all parent associations when
       *            going up the hierarchy; false if the only the primary
       *            parent-child association should be traversed
       */
      public DocumentNavigator(DictionaryService dictionaryService, NodeService nodeService, SearchService searchService,
              NamespacePrefixResolver nspr, boolean followAllParentLinks)
      {
          super();
          this.dictionaryService = dictionaryService;
          this.nodeService = nodeService;
          this.searchService = searchService;
          this.nspr = nspr;
          this.followAllParentLinks = followAllParentLinks;
      }
  
      
      
      public NamespacePrefixResolver getNamespacePrefixResolver()
      {
          return nspr;
      }
  
  
  
      /**
       * Allow this to be set as it commonly changes from one search to the next
       * 
       * @param followAllParentLinks
       *            true
       */
      public void setFollowAllParentLinks(boolean followAllParentLinks)
      {
          this.followAllParentLinks = followAllParentLinks;
      }
  
      public String getAttributeName(Object o)
      {
          // Get the local name
          return ISO9075.encode(((Property) o).qname.getLocalName());
      }
  
      public String getAttributeNamespaceUri(Object o)
      {
          return ((Property) o).qname.getNamespaceURI();
      }
  
      public String getAttributeQName(Object o)
      {
          QName qName = ((Property) o).qname;
          String escapedLocalName = ISO9075.encode(qName.getLocalName());
          if (EqualsHelper.nullSafeEquals(escapedLocalName, qName.getLocalName()))        
          {
              return qName.toString();
          }
          else
          {
              return QName.createQName(qName.getNamespaceURI(), escapedLocalName).toString();
          }
      }
  
      public String getAttributeStringValue(Object o)
      {
          // Only the first property of multi-valued properties is displayed
          // A multivalue attribute makes no sense in the xml world
          return DefaultTypeConverter.INSTANCE.convert(String.class, ((Property) o).value);
      }
  
      public String getCommentStringValue(Object o)
      {
          // There is no attribute that is a comment
          throw new UnsupportedOperationException("Comment string values are unsupported");
      }
  
      public String getElementName(Object o)
      {
          QName qName = ((ChildAssociationRef) o).getQName();
          if(qName == null)
          {
              return "";
          }
          return ISO9075.encode(qName.getLocalName());
      }
  
      public String getElementNamespaceUri(Object o)
      {
          QName qName = ((ChildAssociationRef) o).getQName();
          if(qName == null)
          {
              return "";
          }
          return (qName.getNamespaceURI());
      }
  
      public String getElementQName(Object o)
      {
          QName qName = ((ChildAssociationRef) o).getQName();
          if(qName == null)
          {
              return "";
          }
          String escapedLocalName = ISO9075.encode(qName.getLocalName());
          if (EqualsHelper.nullSafeEquals(escapedLocalName, qName.getLocalName()))        
          {
              return qName.toString();
          }
          else
          {
              return QName.createQName(qName.getNamespaceURI(), escapedLocalName).toString();
          }
      }
  
      public String getElementStringValue(Object o)
      {
          throw new UnsupportedOperationException("Element string values are unsupported");
      }
  
      public String getNamespacePrefix(Object o)
      {
          return ((Namespace) o).prefix;
      }
  
      public String getNamespaceStringValue(Object o)
      {
          return ((Namespace) o).uri;
      }
  
      public String getTextStringValue(Object o)
      {
          throw new UnsupportedOperationException("Text nodes are unsupported");
      }
  
      public boolean isAttribute(Object o)
      {
          return (o instanceof Property);
      }
  
      public boolean isComment(Object o)
      {
          return false;
      }
  
      public boolean isDocument(Object o)
      {
          if (!(o instanceof ChildAssociationRef))
          {
              return false;
          }
          ChildAssociationRef car = (ChildAssociationRef) o;
          return (car.getParentRef() == null) && (car.getQName() == null);
      }
  
      public boolean isElement(Object o)
      {
          return (o instanceof ChildAssociationRef);
      }
  
      public boolean isNamespace(Object o)
      {
          return (o instanceof Namespace);
      }
  
      public boolean isProcessingInstruction(Object o)
      {
          return false;
      }
  
      public boolean isText(Object o)
      {
          return false;
      }
  
      public XPath parseXPath(String o) throws JaxenException
      {
          return new NodeServiceXPath(o, this, null);
      }
  
      // Basic navigation support
  
      public Iterator getAttributeAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI) throws UnsupportedAxisException
      {
          // decode the localname
  