
/****************************************************************************
*
*      Module  : SxPath
*      Fichier : SxPathAxis.c
*      Auteur  : J. Ducloy
*
*      Derniere mise a jour Decembre 2001
*      $Id: SxPathAxis.c,v 1.12 2004/09/22 15:43:09 parmentf Exp $
*
*      This module is moving to SxPathEvalFirst and SxPathEvalSet
*
*
************************************************************************
* 
*     Copyright (C) 2001 CNRS INIST
*
****************************************************************************/
/**
   @file

   @brief Internal functions to interpret SxPathExpressions

   @remark No SxPathResult is used in these functions.
  
   @author &copy; INIST-CNRS
   @author Jacques DUCLOY <DilibMaster@inist.fr>
 */
#include <stdio.h>
#include <string.h>
#include "SxPath.h"
#include "Except.h"
#include <stdlib.h>




/**
  Returns the current SxmlNode (@a x1) only when the SxPathExpression @a
  xp1 matches the current node and is a predicate (an element name, a
  node position, or an element attribute). Increments the value of the
  position, @a pos.  When @a xp1 does not match @a x1, returns NULL.
  
  @param xr1 the result of the evaluation (?)
  @param xp1 the SxPath to evaluate
  @param x1  the Sxml tree on which to evaluate @a xp1
  @param pos the position in the @a xp1 (SxmlContainerInteger)

  @return the node descendant of @a x1 matching @a xp1 if it is a
          terminating predicate.

  @internal @a xr1 is unused in this function!
 */

SxmlNode *SxPathEvalPredicateItem(SxPathResult     *xr1,
			     SxPathExpression *xp1,
			     SxmlNode *predicateItem,
			     SxmlNode *x1,
			     SxmlNode *pos)
{
  int testType;
  char *name1;
  testType=SxmlNodeSubType(predicateItem);
  switch(testType)
    {
    case SXPATH_TEST_NAME:
      name1=SxmlLeafText(predicateItem);
      if(strcmp(name1,SxmlNodeName(x1))==0)return x1;
      else return (NULL);
    
    case SXPATH_PREDICATE_POSITION:
      {
	int posRef;
	posRef=atoi(SxmlLeafText(predicateItem));
	if (posRef==SxmlContainerIntegerValue(pos))return x1;
	return NULL;
      }

    case  SXPATH_RELATIONAL_EXPR:
      {
	SxmlNode *op1;
	SxmlNode *op2;
	SxmlNode *xc1;
	char *targetTag;
	int targetValue;
	char *operator;
	op1=SxmlFirstChild(predicateItem);
	op2=SxmlLastChild(predicateItem);
	operator=SxmlGetAttribute(predicateItem,"operator");
	targetTag=SxmlLeafText(op1);
	targetValue=atoi(SxmlLeafText(op2));
	xc1=SxmlGetFirstChildByTagName(x1, targetTag);
	while (xc1)
	  {
	    if (SxmlIsLeaf(xc1))
	      {
		int nodeValue;
		nodeValue=atoi(SxmlLeafText(xc1));
		if (strcmp(operator,"gt")==0)
		  {
		    if (nodeValue>targetValue) return x1;
		  }
		else if (nodeValue<targetValue) return x1;
	      }
	    xc1=SxmlGetNextSiblingByTagName(xc1, targetTag);
	  }
	return NULL;
      }

    case SXPATH_PREDICATE_ATTRIBUTE:
      {
	char* a1;
	char *v1;
	a1=SxmlGetAttribute(predicateItem,"name");
	v1=SxmlLeafText(predicateItem);
	if(SxmlHasAttribute(x1,a1,v1))return x1;
	else return NULL;
      }
    }
  ExceptSetError("SxPathAxis","NY"," ","predicate ","not yet implemented",2);
  return NULL;
}

SxmlNode *SxPathEvalSiblingPredicates(SxPathResult     *xr1,
				      SxPathExpression *xp1,
				      SxmlNode *nextPredicate,
				      SxmlNode *x1,
				      SxmlNode *pos)
{
  SxmlNode *resu;
  SxmlNode *siblingPredicate;
  resu=SxPathEvalPredicateItem(xr1, xp1, nextPredicate, x1, pos);
  if (!resu)return NULL;
  siblingPredicate=SxmlNextSibling(nextPredicate);
  if (siblingPredicate) return(SxPathEvalSiblingPredicates(xr1, xp1, siblingPredicate,x1,pos));
  return resu;
}

SxmlNode *SxPathEvalPredicates(SxPathResult     *xr1,
			       SxPathExpression *xp1,
			       SxmlNode *x1,
			       SxmlNode *pos)
{
  SxmlNode *predicateItem;

  predicateItem=SxmlFirstChild(xp1);
  if (predicateItem)
    {
      SxmlNode *resu;
      SxmlNode *nextPredicate;
      resu=SxPathEvalPredicateItem(xr1, xp1, predicateItem, x1, pos);
      if (!resu) return NULL;
      nextPredicate=SxmlNextSibling(predicateItem);
      if (nextPredicate)
	{
	  SxmlNode *res1;
	  res1=SxPathEvalSiblingPredicates(xr1, xp1, nextPredicate, x1, pos);
	  if (!res1)return NULL;
	}
    }
  SxmlContainerIntegerIncr(pos);
  return x1;

  /*
  if(SxmlFirstChild(xp1))
    {
      SxmlNode *t1;
      SxmlReset(xp1);
      while((t1=SxmlNextNode(xp1)))
	{
	  int testType;
	  char *name1;
	  testType=SxmlNodeSubType(t1);
	  switch(testType)
	    {
	    case SXPATH_TEST_NAME:
	      name1=SxmlLeafText(t1);
	      if(strcmp(name1,SxmlNodeName(x1))==0)continue;
	      else return (NULL);
	    case SXPATH_PREDICATE_POSITION:
	      {
		int posRef;
		posRef=atoi(SxmlLeafText(t1));
		if (posRef==SxmlContainerIntegerValue(pos))continue;
		SxmlContainerIntegerIncr(pos);
		return NULL;
	      }
	    case SXPATH_PREDICATE_ATTRIBUTE:
	      {
		char* a1;
		char *v1;
		a1=SxmlGetAttribute(t1,"name");
		v1=SxmlLeafText(t1);
		if(SxmlHasAttribute(x1,a1,v1))continue;
		else return NULL;
	      }
	    }
	}
    }
  SxmlContainerIntegerIncr(pos);
  return x1;
  */
}

/**
   Returns the SxmlNode in @a x1 matching @a xp1, beginning with axis
   @c child::

   @param xr1 the result of the evaluation
   @param xp1 the SxPath to evaluate (child::).
   @param x1  the Sxml tree on which to evaluate @a xp1
   @param pos the position in the @a xp1 (SxmlContainerInteger)
   
   @internal @a xr1 is unused in this function (except for
             SxPathFirstSelectAxis).
 */
SxmlNode *SxPathChildFirst(SxPathResult     *xr1,
			 SxPathExpression *xp1,
			 SxmlNode         *x1,
			 SxmlNode         *pos
			 )
{
  SxmlNode *x2;
  SxmlNode *x3;

  SxmlReset(x1);
  x3=NULL;
  while((x2=SxmlNextNode(x1)))
    {
      if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	{
	  SxmlNode *xp2;
	  if((xp2=SxmlNextSibling(xp1)))
	    {
	      SxmlNode *x3;
	      x3=SxPathFirstSelectAxis(xr1,xp2,x2);
	      if(x3) {
		/*	if(pos) { SxmlFree(pos); pos=NULL; } */
		return x3;
	      }
	      else continue;
	    }
	  /*  if(pos) { SxmlFree(pos); pos=NULL; } */
	  return(x2);
	}
    }
  /* if(pos) { SxmlFree(pos); pos=NULL; } */
  return NULL;
}

SxmlNode *SxPathChildPositionFirst(SxPathResult     *xr1,
			 SxPathExpression *xp1,
			 SxmlNode         *x1,
			 SxmlNode         *pos
			 )
{
  int posPath;
  SxmlNode *x2;
  posPath=atoi(SxmlLeafText(xp1));
  x2=SxmlGetChildByPosition(x1, posPath);
  if (x2)
    {
      SxmlNode *xp2;
      if((xp2=SxmlNextSibling(xp1)))
	{
	  SxmlNode *x3;
	  x3=SxPathFirstSelectAxis(xr1,xp2,x2);
	  return x3;
	}
      return x2;
    }
  return NULL;
}



/**
   Returns the SxmlNode in @a x1 matching @a xp1, beginning with axis
   @c attribute::

   @param xr1 the result of the evaluation
   @param xp1 the SxPath to evaluate (attribute::).
   @param x1  the Sxml tree on which to evaluate @a xp1
   @param pos the position in the @a xp1 (SxmlContainerInteger)

   @internal @a xr1 is not used (except in a call to
             SxPathFirstSelectAxis).
 */
SxmlNode *SxPathAttributeFirst(SxPathResult     *xr1,
			     SxPathExpression *xp1,
			     SxmlNode         *x1,
			     SxmlNode         *pos)
{
  SxmlNode *x2;
  SxmlNode *x3;
  SxmlNode *lAtt;

  if ((lAtt=SxmlGetListAttributes(x1)))
    {
      SxmlReset(lAtt);
      x3=NULL;
      while((x2=SxmlNextNode(lAtt)))
	{
	  if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	    {
	      SxmlNode *xp2;
	      if((xp2=SxmlNextSibling(xp1)))
		{
		  SxmlNode *x3;
		  x3=SxPathFirstSelectAxis(xr1,xp2,x2);
		  if(x3){ 
		    /* if(pos) { SxmlFree(pos); pos=NULL; } */
		    return x3;
		  }
		  else continue;
		}
	      /*  if(pos) { SxmlFree(pos); pos=NULL; } */
	      return x2;
	    }
	}
    }
  /*  if(pos) { SxmlFree(pos); pos=NULL; } */
  return NULL;
}

/**
   @brief Returns the first following sibling matching the SxPath.

   Returns a pointer to the SxmlNode that matches the first following
   sibling of @a x1 and the SxPathExpression @a xp1, and possibly
   continues the evaluation of the SxPath by evaluating the next
   sibling of @a xp1 on the found SxmlNode.

   @param xr1 the result of the evaluation
   @param xp1 the SxPath to evaluate (following-sibling).
   @param x1  the Sxml tree on which to evaluate @a xp1
   @param pos the position in the @a xp1 (SxmlContainerInteger)

   @internal @a xr1 is not directly used by this function.
 */
SxmlNode *SxPathFollowingSiblingFirst(SxPathResult     *xr1,
				    SxPathExpression *xp1,
				    SxmlNode *x1,
				    SxmlNode *pos
				    )
{
  SxmlNode *x2;
  SxmlNode *x3;

  x2=x1;
  x3=NULL;
  while((x2=SxmlNextSibling(x2)))
    {
      if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	{
	  SxmlNode *xp2;
	  if((xp2=SxmlNextSibling(xp1)))
	    {
	      SxmlNode *x3;
	      x3=SxPathFirstSelectAxis(xr1,xp2,x2);
	      if(x3){
		/*	if(pos) { SxmlFree(pos); pos=NULL; } */
		return x3;
	      }
	      else continue;
	    }
	  /* if(pos) { SxmlFree(pos); pos=NULL; } */
	  return(x2);
	}
    }
  /* if(pos) { SxmlFree(pos); pos=NULL; } */
  return NULL;
}

/**
   @brief Returns the first deepest descendant of @a x1.

   Returns the first deepest descendant of @a x1, or, if there is
   still another SxPathExpression after @a xp1, the node matching the
   whole SxPathExpression.

   @param xr1 the result of the evaluation
   @param xp1 the SxPath to evaluate (descendant).
   @param x1  the Sxml tree on which to evaluate @a xp1
   @param pos the position in the @a xp1 (SxmlContainerInteger)

   @internal @a xr1 is unused directly in the function (only calls
             suspected of using this parameter: SxPathFirstSelectAxis)
 */
SxmlNode *SxPathDescendantFirst(SxPathResult     *xr1,	
			      SxPathExpression *xp1,
			      SxmlNode *x1,
			      SxmlNode *pos
			      )
{
  SxmlNode *x2;
  SxmlNode *x3;

  SxmlReset(x1);
  x3=NULL;
  while((x2=SxmlNextNode(x1)))
    {
      SxmlNode *x4;
      if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	{
	  SxmlNode *xp2;
	  if((xp2=SxmlNextSibling(xp1)))
	    {
	      SxmlNode *x3;
	      x3=SxPathFirstSelectAxis(xr1,xp2,x2);
	      if(x3){
		/*	if(pos) { SxmlFree(pos); pos=NULL; } */
		return x3;
	      }
	    }
	  /*  if(pos) { SxmlFree(pos); pos=NULL; } */
	  return(x2);
	}
      if((x4=SxPathDescendantFirst(xr1,xp1,x2,pos)))return x4;
    }
  /* if(pos) { SxmlFree(pos); pos=NULL; } */
  return NULL;
}

/**
   Returns the first SxmlNode from @a x1 matching the axis contained in
   @a xp1.  

   Select the axis on top of @a xp1 and calls the appropriate
   function.

   @param xr1 the result of the evaluation
   @param xp1 the SxPath expression (here, an axis among @c child::,
              @c attribute::, @c descendant::, and @c following-sibling:: )
   @param x1  the Sxml tree on which @a xp1 is evaluated.

   @todo See if @a xr1 could be removed from all these functions where
         it is not directly used.

   @see \ref xpath

   @internal @a xr1 is not used! Nor in the calls. It could be removed
             from the parameters!

   @internal 
             @a pos is now freed. And the same has to be done in
             called functions! But this was not done by the previous
             developer!  Maybe there is some reason?

            JD : It was an error. pos must be freeded here !
 */
SxmlNode *SxPathFirstSelectAxis(SxPathResult     *xr1,
			      SxPathExpression *xp1,
			      SxmlNode         *x1)
{
  int xpathNodeType;
  SxmlNode *pos;
  SxmlNode *result;

  xpathNodeType=SxmlNodeSubType(xp1);
  pos=SxmlContainerIntegerCreate(1);
  if(DilibGetTraceLevel()>1)
    {
      printf("*** SxPathFirstSelectAxis \n");
      SxmlDump(xp1);
    }
  switch(xpathNodeType)
    {
    case SXPATH_AXIS_CHILD:
      result=SxPathChildFirst(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_CHILD_POSITION:
      result=SxPathChildPositionFirst(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_ATTRIBUTE:
      result=SxPathAttributeFirst(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_DESCENDANT:
      result=SxPathDescendantFirst(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_FOLLOWING_SIBLING:
      result=SxPathFollowingSiblingFirst(xr1,xp1,x1,pos);
      break;
    default:
      {
	ExceptSetError("SxPathAxis","NY","code ",SxmlNodeName(xp1),"not yet implemented",2);
	if(pos) {
	  SxmlFree(pos);
	}
	return NULL;
      }
    }
  SxmlFree (pos);
  return result;
}

/**
   Launches the evaluation of an SxPathExpression (a location path or a
   union operator) on the @a x1 Sxml tree.

   @param xRes1    the result of the evaluation
   @param locPath1 location path or union operator to evaluate
   @param x1       the Sxml tree on which to evaluate @a locPath1

   @return
            - NULL if @a x1 is NULL.
            - the nodes resulting from the evaluation (SxmlNodeList)

   @todo Check whether or not @a xRes1 is useful.

   @see \ref locationpath "Location Path",
        SxPathSetEval

   @internal @a xRes1 is not used!
 */
SxmlNode *SxPathFirstEval(SxPathResult     *xRes1,
			SxPathExpression *locPath1,
			SxmlNode         *x1)
{
  SxmlNode *xp1;
  int xpathNodeType;

  if(!x1)return NULL;
  xpathNodeType=SxmlNodeSubType(locPath1);
  switch(xpathNodeType)
    {
    case SXPATH_LOCATION_PATH:
      if((xp1=SxmlFirstChild(locPath1)))
	return SxPathFirstSelectAxis(xRes1,xp1,x1);
      return x1;
      
    case SXPATH_OPERATOR_UNION:
      {
	SxmlReset(locPath1);
	while((xp1=SxmlNextNode(locPath1)))
	  {
	    SxmlNode *x2;
	    x2=SxPathFirstEval(xRes1,xp1,x1);
	    if (x2)return x2;
	  }
	return NULL;
      }
    default:
      ExceptSetError("SxPathFirstEval","NY","code ",SxmlNodeName(locPath1),"dont fit or not yet implemented",2);
	return NULL;
    }
}

/**
   Applies the evaluation of the following part of @a xp1 to all the
   nodes of @a set1, and returns the results of these evaluations.

   @param xr1
   @param xp1  SxPath to evaluate
   @param set1 list of nodes already matching the beginning of the
               tree containing @a xp1 (SxmlNodeList).
   @return a list of nodes (SxmlNodeList)

   @warning The name of this function is X<b>p</b>athSetIterSet, and
            not X<b>P</b>athSetIterSet!  
   @internal @a xr1 not directly used!
 */
SxmlNode *SxPathSetIterSet(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *set1)
{
  SxmlNode *xp2;

  if((xp2=SxmlNextSibling(xp1)))
    {
      SxmlNode *set2;
      SxmlNode *x4;
      set2=NULL;
      SxmlReset(set1);
      while((x4=SxmlNodeListNextNode(set1)))
	{
	  SxmlNode *l2;
	  if((l2=SxPathSetSelectAxis(xr1,xp2,x4)))
	    {
	      SxmlNode *x5;
	      if(!set2)set2=SxmlNodeListCreate();
	      SxmlReset(l2);
	      while((x5=SxmlNodeListNextNode(l2)))
		SxmlNodeListAppend(set2,x5);
	      SxmlFree(l2);
	    }
	}
      SxmlFree(set1);
      return set2;
    }
  return set1;
}

/** 
 * Returns a list of nodes, containing all children of @a x1 matching
 * @a xp1.
 *
 * @param xr1  results
 * @param xp1  SxPath to evaluate (axis child::)
 * @param x1   node on which to evaluate
 * @param pos  current evaluated position (SxmlContainerInteger)
 * @return a list a of nodes
 *
 * @internal @a xr1 is not directly used.
 */
SxmlNode *SxPathChildSet(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *x1,
     SxmlNode         *pos)
{
  SxmlNode *x2;
  SxmlNode *lRes;	/* SxmlNodeList */

  SxmlReset(x1);
  lRes=NULL;
  while((x2=SxmlNextNode(x1)))
    {
      if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	{
	  if(!lRes)lRes=SxmlNodeListCreate();
	  SxmlNodeListAppend(lRes,x2);
	}
    }
  if(!lRes)return NULL;
  return SxPathSetIterSet(xr1,xp1,lRes);
}


SxmlNode *SxPathChildPositionSet(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *x1,
     SxmlNode         *pos)
{
  int posPath;
  SxmlNode *x2;
  SxmlNode *lRes;	/* SxmlNodeList */

  posPath=atoi(SxmlLeafText(xp1));
  x2=SxmlGetChildByPosition(x1, posPath);
  if (!x2) return NULL;
  lRes=SxmlNodeListCreate();
  SxmlNodeListAppend(lRes,x2);
  return SxPathSetIterSet(xr1,xp1,lRes);
}

/**
 * Returns the list of descendants of @a x1 which match @a xp1.
 *
 * Appends the results of the evaluation of the SxPathExpression @a xp1
 * to the SxmlNodeList @a lRes.
 * 
 * Launches itself on the children of @a x1.
 *
 * @param xr1  result of the evaluation
 * @param xp1  SxPath to evaluate
 * @param x1   current node on which to evaluate
 * @param lRes list of results (SxmlNodeList)
 * @param pos  current evaluated position (SxmlContainerInteger)
 * @return lRes, the list of results.
 *
 * @internal @a xr1 is not directly used
 */
SxmlNode *SxPathDescendantSetIterative(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode *x1,
     SxmlNode *lRes,
     SxmlNode *pos)
{
  SxmlNode *x2;
  if(SxPathEvalPredicates(xr1,xp1,x1,pos)) 
    {
      if(!lRes)lRes=SxmlNodeListCreate();
      SxmlNodeListAppend(lRes,x1);
    }
  
  SxmlReset(x1);

  while((x2=SxmlNextNode(x1)))
    {
      lRes=SxPathDescendantSetIterative(xr1,xp1,x2,lRes,pos);
    }
  return lRes;
}

/**
   Returns the list of descendants of @a x1 which match @a xp1.
   
   @param xr1  result of the evaluation
   @param xp1  SxPath to evaluate
   @param x1   current node on which to evaluate
   @param pos  current evaluated position (SxmlContainerInteger)
   @return a list of nodes

   @internal @a xr1 is not directly used.
 */
SxmlNode *SxPathDescendantSet(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *x1,
     SxmlNode         *pos)
{
    SxmlNode *lRes;
    lRes=SxPathDescendantSetIterative(xr1,xp1,x1,NULL,pos);
    if(!lRes)return NULL;
    return SxPathSetIterSet(xr1,xp1,lRes);
} 

/**
   Returns a list of nodes, containing all following siblings of @a x1
   which match @a xp1.

   @param xr1 results
   @param xp1 SxPath to evaluate
   @param x1  SxmlTree on which to evaluate the axis (following-sibling)
   @param pos (SxmlContainerInteger)
   @return a list of nodes
 */
SxmlNode *SxPathFollowingSiblingSet(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *x1,
     SxmlNode         *pos)
{
  SxmlNode *x2;
  SxmlNode *lRes;

  x2=x1;
  lRes=NULL;
  while((x2=SxmlNextSibling(x2)))
    {
      if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	{
	  if(!lRes)lRes=SxmlNodeListCreate();
	  SxmlNodeListAppend(lRes,x2);
	}
    }
  if(!lRes)return NULL;
  return SxPathSetIterSet(xr1,xp1,lRes);
}

SxmlNode *SxPathAttributeSet(SxPathResult     *xr1,
			     SxPathExpression *xp1,
			     SxmlNode         *x1,
			     SxmlNode         *pos)
{
  SxmlNode *x2;
  SxmlNode *x3;
  SxmlNode *lAtt;
  SxmlNode *lRes;

  lRes=NULL;
  if ((lAtt=SxmlGetListAttributes(x1)))
    {
      SxmlReset(lAtt);
      x3=NULL;
      while((x2=SxmlNextNode(lAtt)))
	{
	  if(SxPathEvalPredicates(xr1,xp1,x2,pos)) 
	    {
	      SxmlNode *lRes2;

	      if(!lRes)lRes=SxmlNodeListCreate();
	      SxmlNodeListAppend(lRes,x2);
	      lRes2=SxPathSetIterSet(xr1,xp1,lRes);
	      return lRes2;
	    }
	}
    }
  return NULL;
}

/**
   Returns the list of nodes who match @a xp1, in @a x1.

   @param xr1  results
   @param xp1  SxPath to evaluate
   @param x1   node on which to evaluate
   @return a list of nodes matching @a xp1, which needs to be freed (using 
   SxmlFree).
 */
SxmlNode *SxPathSetSelectAxis(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode         *x1)
{
  int xpathNodeType;
  SxmlNode *pos;
  SxmlNode *resu;

  pos=SxmlContainerIntegerCreate(1);
  xpathNodeType=SxmlNodeSubType(xp1);
  resu=NULL;
  switch(xpathNodeType)
    {
    case SXPATH_AXIS_CHILD:
      resu = SxPathChildSet(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_CHILD_POSITION:
      resu = SxPathChildPositionSet(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_DESCENDANT:
      resu = SxPathDescendantSet(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_FOLLOWING_SIBLING:
      resu = SxPathFollowingSiblingSet(xr1,xp1,x1,pos);
      break;
    case SXPATH_AXIS_ATTRIBUTE:
      resu = SxPathAttributeSet(xr1,xp1,x1,pos);
      /* ExceptSetError("SxPathAxis (SxPathSetSelectAxis)","BUG","not yet implemented","","",2); */
      break;
    default:
      ExceptSetError("SxPathAxis (SxPathSetSelectAxis)","NY","not yet implemented","","",2);
      if(pos) { SxmlFree(pos); pos = NULL; }
      return NULL;
    }
  if(pos) { SxmlFree(pos); pos = NULL; }
  return resu;
}

/**
  Returns an SxmlNodeList containing the union of the results of the
  evaluations of the children of the SxPathExpression @a xp1. 
  
  @param xr1  results
  @param xp1  the SxPath to evaluate
  @param x1   the node on which to evaluate @a xp1
  @returns an SxmlNodeList of all the nodes matching @a xp1 on the
           children of @a x1.
  @internal @a xr1 not directly used!
*/
SxmlNode *SxPathSetEvalUnion(
     SxPathResult     *xr1,
     SxPathExpression *xp1,
     SxmlNode *x1
     )
{
  SxmlNode *set1;
  SxmlNode *xp2;

  SxmlReset(xp1);
  set1=NULL;
  while((xp2=SxmlNextNode(xp1)))
    {
      SxmlNode *set2;
      SxmlNode *x2;
      if((set2=SxPathSetEval(xr1,xp2,x1)))
	{
	  if(!set1)set1=SxmlNodeListCreate();
	  SxmlReset(set2);
	  while((x2=SxmlNodeListNextNode(set2)))
	    SxmlNodeListAppend(set1,x2);
	  SxmlFree(set2);
	}
    }
  return set1;
}

/** 
    Launches the evaluation of @a locPath1 (a \ref locationpath
    "location path" or a union operator) on the @a x1 Sxml tree.

    @param xRes1    the result of the evaluation
    @param locPath1 location path or union operator to evaluations
    @param x1       The node on which to evaluation the set of results
    @return the nodes resulting from the evaluation (SxmlNodeList)
    @see \ref locationpath "Location Path",
          SxPathFirstEval
    @todo Check whether or not @a xRes1 is useful.
    @internal @a xRes1 is not used!
 */
SxmlNode *SxPathSetEval(
     SxPathResult     *xRes1,
     SxPathExpression *locPath1,
     SxmlNode         *x1)
{
  SxmlNode *xp1;
  int xpathNodeType;
  
  if(!x1)return NULL;
  xpathNodeType=SxmlNodeSubType(locPath1);
  switch(xpathNodeType)
    {
    case SXPATH_LOCATION_PATH:
      if((xp1=SxmlFirstChild(locPath1)))
	return SxPathSetSelectAxis(xRes1,xp1,x1);
      return x1;
    case SXPATH_OPERATOR_UNION:
      return SxPathSetEvalUnion(xRes1,locPath1,x1);
    default:
      ExceptSetError("SxPathFirstEval","NY","code ",SxmlNodeName(locPath1),"does not fit or not yet implemented",2);
      return NULL;
    }
}
  

/**
   Does nothing else than returning x1.

   @param xRes1
   @param xp1
   @param x1
   @return x1

   @internal Perhaps planned to do it another way?
 */
SxmlNode * SxPathListNodeAxis(SxPathResult     *xRes1,
			    SxPathExpression *xp1,
			    SxmlNode         *x1)
{
  return x1;
}


/**
   Does nothing else than returning x1.

   @param xRes1
   @param locPath1
   @param x1
   @return x1
   @see locationpath "Location Path"
   @internal Does not seem to be very useful yet!
 */
SxmlNode *SxPathListNodeEval(SxPathResult     *xRes1,
			   SxPathExpression *locPath1,
			   SxmlNode         *x1)
{
  SxmlNode *xp1;
  if(!x1)return NULL;
  if((xp1=SxmlFirstChild(locPath1)))
    return SxPathListNodeAxis(xRes1,xp1,x1);
  return x1;
}

/**
 * Searches among the children of @a x1, the first child with a tag
 * name matching the test name of the test node, child of the
 * expression node of @a step1 and returns it.
 *
 * Also, the nextNode of @a step1 is set to the found child, and its
 * contextNode too.
 *
 * When no child of @a x1 matches, NULL pointer is returned.
 *
 * @param step1
 * @param x1
 */
SxmlNode *SxPathChildReset(SxPathResultStep *step1,
			 SxmlNode         *x1)
{
  SxmlNode *x2;
  SxmlNode *expr1;
  SxmlNode *testNode;
  char *n1;
  int testType;

  expr1=SxPathResultStepExpressionNode(step1);
  testNode=SxmlFirstChild(expr1);
  testType=SxmlNodeSubType(testNode);
  
  n1=SxmlLeafText(testNode);

  if ((x2=SxmlFirstChild(x1)))
    {
      do
	{
	  switch(testType)
	    {
	    case SXPATH_TEST_NAME:
	      if(strcmp(n1,SxmlNodeName(x2))==0)
		{
		  SxmlSetNextNodeProperty(step1,x2);
		  SxPathSetResultStepContextNode(step1,x2);
		  return x2;
		}
	    }
	}while((x2=SxmlNextSibling(x2)));
    }
  return NULL;
}


/**
   Sets the NextNodeProperty and the ContextNode of @a step1, to the
   first child of @a x1 which name matches the attribute "name" of the
   ExpressionNode of @a step1.

   Returns NULL if no child matches the condition.

   @param step1
   @param x1
   @returns the first child of @a x1 which name matches the attribute
   "name" of the ExpressionNode of @a step1
   @see SxPathResultStep
 */
SxmlNode *SxPathChildNameReset(SxPathResultStep *step1,
			     SxmlNode         *x1)
{
  SxmlNode *x2;
  SxmlNode *expr1; /* SxPathExpression ? */
  char *n1;

  expr1=SxPathResultStepExpressionNode(step1);
  n1=SxmlGetAttribute(expr1,"name");

  if ((x2=SxmlFirstChild(x1)))
    {
      do
	{
	  if(strcmp(n1,SxmlNodeName(x2))==0)
	    {
	      SxmlSetNextNodeProperty(step1,x2);
	      SxPathSetResultStepContextNode(step1,x2);
	      return x2;
	    }
	}while((x2=SxmlNextSibling(x2)));
    }
  return NULL;
}


/**
   Finds the first sibling of @a step1's NextNode that matches @a
   step1's ExpressionNode's "name" attribute. Sets @a step1's NextNode
   and ContextNode to the found SxmlNode, when it exists. Otherwise,
   set these values to NULL.

   @param step1
   @returns @a step1's NextNode.
 */
SxmlNode *SxPathChildNameNextNode(SxPathResultStep *step1)
{

  SxmlNode *x2;
  SxmlNode *x3;
  SxmlNode *expr1; /* SxPathExpression ? */
  char *n1;

  expr1=SxPathResultStepExpressionNode(step1);
  n1=SxmlGetAttribute(expr1,"name");

  x2=SxmlNextNodeProperty(step1);
  if(!x2)return NULL;
  x3=SxmlNextSibling(x2);
  SxmlSetNextNodeProperty(step1,NULL);
  if(!x3)return x2;
  do
    {
      if(strcmp(n1,SxmlNodeName(x3))==0)
	{
	  SxmlSetNextNodeProperty(step1,x3);
	  SxPathSetResultStepContextNode(step1,x2);
	  return x2;
	}
    } while ((x3=SxmlNextSibling(x3)));
  return x2;
}

/**
 * Find the next node matching the step, in the siblings of the
 * context node of @a step1. Sets the next node of @a step1 to the
 * found node. Sets the context node of @a step1 to its previous next
 * node.
 *
 * @param step1 SxPathResultStep
 * @return NULL pointer when no node is found.
 */
SxmlNode *SxPathChildNextNode(SxPathResultStep *step1)
{

  SxmlNode *x2;
  SxmlNode *x3;
  SxmlNode *expr1;    /* SxPathExpression ? */
  SxmlNode *testNode; /* SxPathExpression ? */
  char *n1;
  int testType;

  expr1=SxPathResultStepExpressionNode(step1);
  testNode=SxmlFirstChild(expr1);
  testType=SxmlNodeSubType(testNode);
  
  n1=SxmlLeafText(testNode);

  x2=SxmlNextNodeProperty(step1);
  if(!x2)return NULL;
  x3=SxmlNextSibling(x2);
  SxmlSetNextNodeProperty(step1,NULL);
  if(!x3)return x2;
  do
    {
      switch(testType)
	{
	case SXPATH_TEST_NAME:
	  if(strcmp(n1,SxmlNodeName(x3))==0)
	    {
	      SxmlSetNextNodeProperty(step1,x3);
	      SxPathSetResultStepContextNode(step1,x2);
	      return x2;
	    }
	}
    } while ((x3=SxmlNextSibling(x3)));
  return x2;
}

