code: package com.taxonic.carml.logical_source_resolver;
  
  import static org.hamcrest.MatcherAssert.assertThat;
  import static org.hamcrest.core.Is.is;
  import static org.hamcrest.text.IsEqualCompressingWhiteSpace.equalToCompressingWhiteSpace;
  
  import com.google.common.collect.Iterables;
  import com.google.common.collect.Lists;
  import com.taxonic.carml.engine.EvaluateExpression;
  import com.taxonic.carml.logical_source_resolver.LogicalSourceResolver.ExpressionEvaluatorFactory;
  import com.taxonic.carml.model.LogicalSource;
  import com.taxonic.carml.model.TriplesMap;
  import com.taxonic.carml.model.impl.CarmlLogicalSource;
  import com.taxonic.carml.util.RmlMappingLoader;
  import com.taxonic.carml.vocab.Rdf.Ql;
  import java.util.List;
  import java.util.Set;
  import java.util.function.Function;
  import net.sf.saxon.s9api.XdmItem;
  import org.eclipse.rdf4j.rio.RDFFormat;
  import org.junit.Before;
  import org.junit.Test;
  
  public class XPathResolverTest {
  
  	private static final String BOOK_ONE =
  			"<book category=\"cooking\">\r\n" +
  			"  <title lang=\"en\">Everyday Italian</title>\r\n" +
  			"  <author>Giada De Laurentiis</author>\r\n" +
  			"  <year>2005</year>\r\n" +
  			"  <price>30.00</price>\r\n" +
  			"</book>";
  
  	private static final String SOURCE =
  			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
  			"\r\n" +
  			"<bookstore>\r\n" +
  			"\r\n" +
  			BOOK_ONE +
  			"\r\n" +
  			"<book category=\"children\">\r\n" +
  			"  <title lang=\"en\">Harry Potter</title>\r\n" +
  			"  <author>J K. Rowling</author>\r\n" +
  			"  <year>2005</year>\r\n" +
  			"  <price>29.99</price>\r\n" +
  			"</book>\r\n" +
  			"\r\n" +
  			"</bookstore>";
  
  	private static final LogicalSource LSOURCE =
  			new CarmlLogicalSource(SOURCE, "/bookstore/*", Ql.XPath);
  
  	private static final String SOURCE_NS =
  			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
  			"\r\n" +
  			"<ex:bookstore xmlns:ex=\"http://www.example.com/books/1.0/\">\r\n" +
  			"\r\n" +
  			"<ex:book category=\"children\">\r\n" +
  			"  <ex:title lang=\"en\">Harry Potter</ex:title>\r\n" +
  			"  <ex:author>J K. Rowling</ex:author>\r\n" +
  			"  <ex:year>2005</ex:year>\r\n" +
  			"  <ex:price>29.99</ex:price>\r\n" +
  			"</ex:book>\r\n" +
  			"\r\n" +
  			"</ex:bookstore>";
  
  	private static final Function<Object, String> nsSourceResolver = s -> SOURCE_NS;
  
  	private static final Function<Object, String> sourceResolver = s -> s.toString();
  
  	private XPathResolver xpathResolver;
  	private Iterable<XdmItem> nodeIterator;
  	private List<XdmItem> nodes;
  
  	@Before
  	public void init() {
  		xpathResolver = new XPathResolver();
  		nodeIterator = xpathResolver.bindSource(LSOURCE, sourceResolver).get();
  		nodes = Lists.newArrayList(nodeIterator);
  	}
  
  	@Test
  	public void sourceIterator_givenXmlSourceAndBookNodeSelector_shoulReturnAllNodes() {
  		assertThat(nodes.size(), is(2));
  		assertThat(nodes.get(0).toString(), is(equalToCompressingWhiteSpace(BOOK_ONE)));
  	}
  
  	@Test
  	public void expressionEvaluator_givenExpression_shoulReturnCorrectValue() {
  		String expression = "./author/lower-case(.)";
  		ExpressionEvaluatorFactory<XdmItem> evaluatorFactory =
  				xpathResolver.getExpressionEvaluatorFactory();
  		EvaluateExpression evaluateExpression = evaluatorFactory.apply(nodes.get(0));
  		assertThat(evaluateExpression.apply(expression).get(), is("giada de laurentiis"));
  	}
  
  	@Test
  	public void expressionEvaluatorWithoutAutoTextExtraction_givenExpression_shoulReturnCorrectValue() {
  		String expression = "./author";
  		ExpressionEvaluatorFactory<XdmItem> evaluatorFactory =
  				xpathResolver.getExpressionEvaluatorFactory();
  		EvaluateExpression evaluateExpression = evaluatorFactory.apply(nodes.get(0));
  		assertThat(evaluateExpression.apply(expression).get(), is("Giada De Laurentiis"));
  
  		// redefine XPath resolver to not auto-extract text
  		boolean autoExtractNodeText = false;
  		xpathResolver = new XPathResolver(autoExtractNodeText);
  
  		nodeIterator = xpathResolver.bindSource(LSOURCE, sourceResolver).get();
  		evaluatorFactory = xpathResolver.getExpressionEvaluatorFactory();
  
  		nodes = Lists.newArrayList(nodeIterator);
  		evaluateExpression = evaluatorFactory.apply(nodes.get(0));
  		assertThat(evaluateExpression.apply(expression).get(), is("<author>Giada De Laurentiis</author>"));
  	}
  
  	@Test
  	public void expressionEvaluator_givenExpressionWithNamespace_shoulReturnCorrectValue() {
  		Set<TriplesMap> mapping =
  				RmlMappingLoader
  					.build()
  						.load(RDFFormat.TURTLE,
  								XPathResolverTest.class.getResourceAsStream("xmlns.rml.ttl"));
  
  		TriplesMap tMap = Iterables.getOnlyElement(mapping);
  
  		LogicalSource lSource = tMap.getLogicalSource();
  
  		xpathResolver = new XPathResolver();
  		nodeIterator = xpathResolver.bindSource(lSource, nsSourceResolver).get();
  		nodes = Lists.newArrayList(nodeIterator);
  
  		String expression = "./ex:author/lower-case(.)";
  		ExpressionEvaluatorFactory<XdmItem> evaluatorFactory =
  				xpathResolver.getExpressionEvaluatorFactory();
  		EvaluateExpression evaluateExpression = evaluatorFactory.apply(nodes.get(0));
  		assertThat(evaluateExpression.apply(expression).get(), is("j k. rowling"));
  	}
  }
  