diff --git a/src/Xpath/Compiler.php b/src/Xpath/Compiler.php
index 9ad2fde..1c28817 100644
--- a/src/Xpath/Compiler.php
+++ b/src/Xpath/Compiler.php
@@ -18,9 +18,13 @@ final class Compiler
*/
private $functions;
/**
- * @var SequenceConstructor
+ * @var ReturnXsSequenceFunction
*/
private $sequenceConstructor;
+ /**
+ * @var ReturnXsSequenceFunction
+ */
+ private $forLoopConstructor;
/**
* @param FunctionMap $functions
@@ -29,6 +33,7 @@ public function __construct(FunctionMap $functions)
{
$this->functions = $functions;
$this->sequenceConstructor = new ReturnXsSequenceFunction(new SequenceConstructor());
+ $this->forLoopConstructor = new ForLoopConstructor();
}
/**
@@ -43,7 +48,7 @@ public function compile($xpathExpression, DOMNode $currentElement)
foreach ($lexer as $token) {
$nextToken = $lexer->peek($lexer->key() + 1);
if ($nextToken === '(') {
- $resultTokens = array_merge($resultTokens, $this->createFunctionTokens($lexer, $token, $currentElement));
+ $resultTokens = array_merge($resultTokens, $this->createFunctionTokens($lexer, $currentElement));
continue;
}
@@ -52,6 +57,13 @@ public function compile($xpathExpression, DOMNode $currentElement)
continue;
}
+ if ($this->isForLoop($lexer)) {
+ array_pop($resultTokens);
+ array_pop($resultTokens);
+ $resultTokens = array_merge($resultTokens, $this->createForLoop($lexer, $currentElement));
+ continue;
+ }
+
$resultTokens[] = $token;
}
@@ -60,11 +72,11 @@ public function compile($xpathExpression, DOMNode $currentElement)
/**
* @param Lexer $lexer
- * @param $token
- * @param $currentElement
+ * @param DOMNode $currentElement
* @return string[]
*/
- private function createFunctionTokens (Lexer $lexer, $token, $currentElement) {
+ private function createFunctionTokens (Lexer $lexer, DOMNode $currentElement) {
+ $token = $lexer->current();
$namespaces = FetchNamespacesFromNode::fetch($currentElement);
$functionName = $this->convertTokenToFunctionName($token, $namespaces);
@@ -109,18 +121,27 @@ private function isSequence (Lexer $lexer) {
if ($lexer->key() === 0) {
return true;
} else {
-// $prevToken = $lexer->peek($lexer->key() - 1);
-// return preg_match('/[\i-[:]][\c-[:]]*/', $prevToken) === 0;
- return false;
+ $prevToken = $lexer->peek($lexer->key() - 1);
+ return $prevToken === '(' || preg_match('/\s/', $prevToken) === 1;
}
}
/**
* @param Lexer $lexer
- * @param $currentElement
+ * @param DOMNode $currentElement
* @return string[]
*/
- private function createSequenceTokens (Lexer $lexer, $currentElement) {
+ private function createSequenceTokens (Lexer $lexer, DOMNode $currentElement) {
return $this->sequenceConstructor->replace($lexer, $currentElement);
}
+
+ private function isForLoop(Lexer $lexer)
+ {
+ return ($lexer->current() === 'to' && preg_match('/\s/', $lexer->peek($lexer->key() - 1)) === 1);
+ }
+
+ private function createForLoop(Lexer $lexer, DOMNode $currentElement)
+ {
+ return $this->forLoopConstructor->replace($lexer, $currentElement);
+ }
}
diff --git a/src/Xpath/ForLoopConstructor.php b/src/Xpath/ForLoopConstructor.php
new file mode 100644
index 0000000..6ca087d
--- /dev/null
+++ b/src/Xpath/ForLoopConstructor.php
@@ -0,0 +1,61 @@
+peek($lexer->key() - 2);
+ $resultTokens[] = ',';
+ $resultTokens[] = $lexer->peek($lexer->key() + 2);
+ $resultTokens[] = ')';
+ $resultTokens[] = '/';
+ $resultTokens[] = 'xs:sequence';
+ $resultTokens[] = '/';
+ $resultTokens[] = '*';
+
+ $lexer->seek($lexer->key() + 2);
+
+ return $resultTokens;
+ }
+
+ /**
+ * @param $first
+ * @param $last
+ * @return mixed
+ * @throws \Genkgo\Xsl\Schema\Exception\UnknownSequenceItemException
+ */
+ public static function call($first, $last)
+ {
+ return XsSequence::fromArray(range($first, $last));
+ }
+}
diff --git a/tests/Integration/Schema/XsSequenceTest.php b/tests/Integration/Schema/XsSequenceTest.php
deleted file mode 100644
index 0263670..0000000
--- a/tests/Integration/Schema/XsSequenceTest.php
+++ /dev/null
@@ -1,12 +0,0 @@
-transformFile('Stubs/Schema/string-sequence.xsl');
- $this->assertContains('a b c', $result);
- }
-
-}
diff --git a/tests/Integration/Xpath/ForLoopTest.php b/tests/Integration/Xpath/ForLoopTest.php
new file mode 100644
index 0000000..43402df
--- /dev/null
+++ b/tests/Integration/Xpath/ForLoopTest.php
@@ -0,0 +1,18 @@
+transformFile('Stubs/Xpath/ForLoop/simple.xsl');
+ $this->assertContains('1 2 3 4 5 6 7 8 9 10', $result);
+ }
+
+ public function testForEach()
+ {
+ $result = $this->transformFile('Stubs/Xpath/ForLoop/for-each.xsl');
+ $this->assertContains('12345678910', $result);
+ }
+
+}
diff --git a/tests/Integration/Xpath/SequenceTest.php b/tests/Integration/Xpath/SequenceTest.php
index b8664ef..744de41 100644
--- a/tests/Integration/Xpath/SequenceTest.php
+++ b/tests/Integration/Xpath/SequenceTest.php
@@ -3,6 +3,18 @@
class SequenceTest extends AbstractXpathTest
{
+ public function testConstructorString()
+ {
+ $result = $this->transformFile('Stubs/Xpath/Sequence/constructor-string.xsl');
+ $this->assertContains('a b c', $result);
+ }
+
+ public function testConstructorInteger()
+ {
+ $result = $this->transformFile('Stubs/Xpath/Sequence/constructor-integer.xsl');
+ $this->assertContains('1 2 3', $result);
+ }
+
public function testReverse()
{
$this->assertEquals(
diff --git a/tests/Stubs/Xpath/ForLoop/for-each.xsl b/tests/Stubs/Xpath/ForLoop/for-each.xsl
new file mode 100644
index 0000000..15dc499
--- /dev/null
+++ b/tests/Stubs/Xpath/ForLoop/for-each.xsl
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Stubs/Xpath/ForLoop/simple.xsl b/tests/Stubs/Xpath/ForLoop/simple.xsl
new file mode 100644
index 0000000..6d644ee
--- /dev/null
+++ b/tests/Stubs/Xpath/ForLoop/simple.xsl
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Stubs/Xpath/Sequence/constructor-integer.xsl b/tests/Stubs/Xpath/Sequence/constructor-integer.xsl
new file mode 100644
index 0000000..0c0936f
--- /dev/null
+++ b/tests/Stubs/Xpath/Sequence/constructor-integer.xsl
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Stubs/Schema/string-sequence.xsl b/tests/Stubs/Xpath/Sequence/constructor-string.xsl
similarity index 100%
rename from tests/Stubs/Schema/string-sequence.xsl
rename to tests/Stubs/Xpath/Sequence/constructor-string.xsl
diff --git a/tests/Stubs/Xpath/Sequence/reverse.xsl b/tests/Stubs/Xpath/Sequence/reverse.xsl
index c2e449a..96017dd 100644
--- a/tests/Stubs/Xpath/Sequence/reverse.xsl
+++ b/tests/Stubs/Xpath/Sequence/reverse.xsl
@@ -3,7 +3,7 @@
-
+
\ No newline at end of file