Esempio n. 1
0
 public function valid()
 {
     if ($this->length > 0 && $this->offset + $this->length <= $this->count) {
         return false;
     }
     if (is_string($this->name) && strpos($this->name, '|') !== false) {
         $this->name = explode('|', $this->name);
     }
     if (is_array($this->name)) {
         $tags = [];
         foreach ($this->name as $name) {
             try {
                 $get_tag = \ebi\Xml::extract($this->plain, $name);
                 $tags[$get_tag->cur()] = $get_tag;
             } catch (\ebi\exception\NotFoundException $e) {
             }
         }
         if (empty($tags)) {
             return false;
         }
         ksort($tags, SORT_NUMERIC);
         foreach ($tags as $this->tag) {
             return true;
         }
     }
     try {
         $this->tag = \ebi\Xml::extract($this->plain, $this->name);
         return true;
     } catch (\ebi\exception\NotFoundException $e) {
     }
     return false;
 }
Esempio n. 2
0
 /**
  * @plugin ebi.Temaplte
  * @param string $src
  * @return Ambigous <string, string, mixed>|string
  */
 public function before_template($src)
 {
     /**
      * @param string $path テンプレートパーツのファイルがあるディレクトリ
      */
     $path = \ebi\Util::path_slash(\ebi\Conf::get('path', \ebi\Conf::resource_path('parts')), null, true);
     return \ebi\Xml::find_replace($src, 'rt:parts', function ($xml) use($path) {
         $href = \ebi\Util::path_absolute($path, $xml->in_attr('href'));
         if (!is_file($href)) {
             throw new \ebi\exception\InvalidArgumentException($href . ' not found');
         }
         return file_get_contents($href);
     });
 }
Esempio n. 3
0
 private static function parse($html, $url)
 {
     $forms = [];
     try {
         foreach (\ebi\Xml::extract($html, 'body')->find('form') as $key => $formtag) {
             $form = new \stdClass();
             $form->name = $formtag->in_attr('name', $formtag->in_attr('id', $key));
             $form->action = \ebi\Util::path_absolute($url, $formtag->in_attr('action', $url));
             $form->method = strtolower($formtag->in_attr('method', 'get'));
             $form->multiple = false;
             $form->element = [];
             foreach ($formtag->find('input') as $count => $input) {
                 $obj = new \stdClass();
                 $obj->name = $input->in_attr('name', $input->in_attr('id', 'input_' . $count));
                 $obj->type = strtolower($input->in_attr('type', 'text'));
                 $obj->value = self::htmldecode($input->in_attr('value'));
                 $obj->selected = 'selected' === strtolower($input->in_attr('checked', $input->in_attr('checked')));
                 $obj->multiple = false;
                 $form->element[] = $obj;
             }
             foreach ($formtag->find('textarea') as $count => $input) {
                 $obj = new \stdClass();
                 $obj->name = $input->in_attr('name', $input->in_attr('id', 'textarea_' . $count));
                 $obj->type = 'textarea';
                 $obj->value = self::htmldecode($input->value());
                 $obj->selected = true;
                 $obj->multiple = false;
                 $form->element[] = $obj;
             }
             foreach ($formtag->find('select') as $count => $input) {
                 $obj = new \stdClass();
                 $obj->name = $input->in_attr('name', $input->in_attr('id', 'select_' . $count));
                 $obj->type = 'select';
                 $obj->value = [];
                 $obj->selected = true;
                 $obj->multiple = 'multiple' == strtolower($input->param('multiple', $input->attr('multiple')));
                 foreach ($input->find('option') as $count => $option) {
                     $op = new \stdClass();
                     $op->value = self::htmldecode($option->in_attr('value', $option->value()));
                     $op->selected = 'selected' == strtolower($option->in_attr('selected', $option->in_attr('selected')));
                     $obj->value[] = $op;
                 }
                 $form->element[] = $obj;
             }
             $forms[] = $form;
         }
     } catch (\ebi\exception\NotFoundException $e) {
     }
     return $forms;
 }
Esempio n. 4
0
 /**
  * Set template
  * @param string $template_path Relative path from resource_path
  * @param mixed{} $vars bind variables
  * @return $this
  */
 public function set_template($template_path, $vars = [])
 {
     /**
      * @param string $path Email template resources root
      */
     $resource_path = \ebi\Conf::get('resource_path', \ebi\Conf::resource_path('mail'));
     $path = \ebi\Util::path_absolute($resource_path, $template_path);
     if (!is_file($path)) {
         throw new \ebi\exception\InvalidArgumentException($template_path . ' not found');
     }
     $xml = \ebi\Xml::extract(file_get_contents($path), 'mail');
     try {
         try {
             $from = $xml->find_get('from');
             $this->from($from->in_attr('address'), $from->in_attr('name'));
         } catch (\ebi\exception\NotFoundException $e) {
         }
         foreach ($xml->find('to') as $to) {
             $this->to($to->in_attr('address'), $to->in_attr('name'));
         }
         try {
             $this->return_path($xml->find_get('return_path')->in_attr('address'));
         } catch (\ebi\exception\NotFoundException $e) {
         }
         /**
          * @param string $xtc_name xtc query key
          */
         $xtc_name = \ebi\Conf::get('xtc_name', 'xtc');
         $xtc = self::xtc($template_path);
         $this->header['X-T-Code'] = $xtc;
         $vars['t'] = new \ebi\FlowHelper();
         $vars['xtc'] = [$xtc_name => $xtc];
         $subject = trim(str_replace(["\r\n", "\r", "\n"], '', $xml->find_get('subject')->value()));
         $template = new \ebi\Template();
         $template->cp($vars);
         $body_xml = $xml->find_get('body');
         $signature = $body_xml->in_attr('signature');
         $signature_text = '';
         if (!empty($signature)) {
             $sig_path = \ebi\Util::path_absolute($resource_path, $signature);
             if (!is_file($sig_path)) {
                 throw new \ebi\exception\InvalidArgumentException($signature . ' not found');
             }
             $sig_xml = \ebi\Xml::extract(file_get_contents($sig_path), 'mail');
             $signature_text = \ebi\Util::plain_text(PHP_EOL . $sig_xml->find_get('signature')->value() . PHP_EOL);
         }
         $message = $template->get(\ebi\Util::plain_text(PHP_EOL . $body_xml->value() . PHP_EOL) . $signature_text);
         $this->message($message);
         $this->subject($template->get($subject));
         try {
             $html = $xml->find_get('html');
             $html_path = \ebi\Util::path_absolute($resource_path, $html->in_attr('src', preg_replace('/^(.+)\\.\\w+$/', '\\1', $path) . '.html'));
             foreach ($html->find('media') as $media) {
                 $file = \ebi\Util::path_absolute($resource_path, $media->in_attr('src'));
                 if (!is_file($file)) {
                     throw new \ebi\exception\InvalidArgumentException($media->in_attr('src') . ' invalid media');
                 }
                 $this->media($media->in_attr('src'), file_get_contents($file));
             }
             $template = new \ebi\Template();
             $template->cp($vars);
             $this->html($template->read($html_path));
         } catch (\ebi\exception\NotFoundException $e) {
         }
         foreach ($xml->find('attach') as $attach) {
             $file = \ebi\Util::path_absolute($resource_path, $attach->in_attr('src'));
             if (!is_file($file)) {
                 throw new \ebi\exception\InvalidArgumentException($attach->in_attr('src') . ' invalid media');
             }
             $this->attach($attach->in_attr('name', $attach->in_attr('src')), file_get_contents($file));
         }
         return $this;
     } catch (\ebi\exception\NotFoundException $e) {
         throw new \ebi\exception\InvalidArgumentException($template_path . ' invalid data');
     }
 }
Esempio n. 5
0
$p = "<abc><def>111</def></abc>";
$x = \ebi\Xml::extract($p, 'abc');
eq("abc", $x->name());
$p = "<abc><def>111</def></abc>";
$x = \ebi\Xml::extract($p, "def");
eq("def", $x->name());
eq(111, $x->value());
try {
    $p = "aaaa";
    \ebi\Xml::extract($p, 'abc');
    fail();
} catch (\ebi\exception\NotFoundException $e) {
}
try {
    $p = "<abc>sss</abc>";
    \ebi\Xml::extract($p, "def");
    fail();
} catch (\ebi\exception\NotFoundException $e) {
}
$p = "<abc>sss</a>";
$x = \ebi\Xml::extract($p, 'abc');
eq("<abc />", $x->get());
$p = "<abc>0</abc>";
$x = \ebi\Xml::extract($p, 'abc');
eq("abc", $x->name());
eq("0", $x->value());
$p = "<abc />";
$x = \ebi\Xml::extract($p, "abc");
$p = "<abc/>";
$x = \ebi\Xml::extract($p, "abc");
Esempio n. 6
0
 public function before_template($src)
 {
     return \ebi\Xml::find_replace($src, 'rt:paginator', function ($xml) {
         $param = '$' . $xml->in_attr('param', 'paginator');
         $navi = array_change_key_case(array_flip(explode(',', $xml->in_attr('navi', 'prev,next,first,last,counter'))));
         $counter = $xml->in_attr('counter', 10);
         $lt = strtolower($xml->in_attr('lt', 'true'));
         $href = $xml->in_attr('href', '?');
         $uniq = uniqid('');
         $counter_var = '$__counter__' . $uniq;
         $func = '';
         if ($lt == 'false') {
             $func .= sprintf('<?php if(%s->is_dynamic() || %s->total() > %s->limit()){ ?>', $param, $param, $param);
         }
         $func .= sprintf('<?php try{ ?><?php if(%s instanceof \\ebi\\Paginator){ ?><ul class="pagination">', $param);
         if (isset($navi['prev'])) {
             $func .= sprintf('<?php if(%s->is_prev()){ ?><li class="prev"><a href="%s{%s.query_prev()}" rel="prev"><?php }else{ ?><li class="prev disabled"><a><?php } ?>&laquo;</a></li>', $param, $href, $param);
         }
         if (isset($navi['first'])) {
             $func .= sprintf('<?php if(!%s->is_dynamic() && %s->is_first(%d)){ ?><li><a href="%s{%s.query(%s.first())}">{%s.first()}</a></li><li class="disabled"><a>...</a></li><?php } ?>', $param, $param, $counter, $href, $param, $param, $param);
         }
         if (isset($navi['counter'])) {
             $func .= sprintf('<?php if(!%s->is_dynamic()){ ?>', $param) . sprintf('<?php if(%s->total() == 0){ ?>', $param) . sprintf('<li class="active"><a>1</a></li>') . '<?php }else{ ?>' . sprintf('<?php for(%s=%s->which_first(%d);%s<=%s->which_last(%d);%s++){ ?>', $counter_var, $param, $counter, $counter_var, $param, $counter, $counter_var) . sprintf('<?php if(%s == %s->current()){ ?>', $counter_var, $param) . sprintf('<li class="active"><a>{%s}</a></li>', $counter_var) . '<?php }else{ ?>' . sprintf('<li><a href="%s{%s.query(%s)}">{%s}</a></li>', $href, $param, $counter_var, $counter_var) . '<?php } ?>' . '<?php } ?>' . '<?php } ?>' . '<?php } ?>';
         }
         if (isset($navi['last'])) {
             $func .= sprintf('<?php if(!%s->is_dynamic() && %s->is_last(%d)){ ?><li class="disabled"><a>...</a></li><li><a href="%s{%s.query(%s.last())}">{%s.last()}</a></li><?php } ?>', $param, $param, $counter, $href, $param, $param, $param);
         }
         if (isset($navi['next'])) {
             $func .= sprintf('<?php if(%s->is_next()){ ?><li class="next"><a href="%s{%s.query_next()}" rel="next"><?php }else{ ?><li class="next disabled"><a><?php } ?>&raquo;</a></li>', $param, $href, $param);
         }
         $func .= "<?php } ?><?php }catch(\\Exception \$e){} ?></ul>";
         if ($lt == 'false') {
             $func .= sprintf('<?php } ?>', $param);
         }
         return $func;
     });
 }
Esempio n. 7
0
eq('XYZ', $x->find_get('abc/def/ghi', 1)->value());
$x = \ebi\Xml::anonymous("<asd><abc><def><ghi>ABC</ghi><ghi>XYZ</ghi></def></abc></asd>");
eq('XYZ', $x->find_get('abc/def/ghi', 1)->value());
$x = \ebi\Xml::anonymous("<asd><abc><def><jkl>aaa</jkl><ghi>ABC</ghi><jkl>bbb</jkl><ghi>XYZ</ghi></def></abc></asd>");
eq('XYZ', $x->find_get('abc/def/ghi', 1)->value());
$x = \ebi\Xml::anonymous("<asd><abc><def><jkl>aaa</jkl><ghi>ABC</ghi><jkl>bbb</jkl><ghi>XYZ</ghi></def></abc></asd>");
eq('bbb', $x->find_get('abc/def/jkl', 1)->value());
$x = \ebi\Xml::anonymous("<asd><abc><def><jkl>aaa</jkl><ghi>ABC</ghi><jkl>bbb</jkl><ghi>XYZ</ghi></def></abc></asd>");
eq('bbb', $x->find_get('abc/def/ghi|jkl', 2)->value());
$x = \ebi\Xml::anonymous("<xml><a><x>A</x></a><c><x>C</x></c><b><x>B</x></b></xml>");
eq('C', $x->find_get('b|c/x')->value());
$x = \ebi\Xml::anonymous("<xml> <a><b><e>NO1</e></b></a> <a><b><c>A</c></b></a> <a><b><c>B</c></b></a>  <a><b><c>C</c></b></a> </xml>");
eq('A', $x->find_get('a/b/c')->value());
$i = 0;
foreach ($x->find('a/b/c') as $f) {
    $i++;
}
eq(1, $i);
$x = \ebi\Xml::anonymous("<xml> <a><b><e>NO1</e></b></a> <a><b><c>A</c></b></a> <a><b><c>B</c></b></a>  <a><b><c>C</c></b></a> </xml>");
try {
    $x->find_get('a/b/c', 1)->value();
    fail();
} catch (\ebi\exception\NotFoundException $e) {
}
$x = \ebi\Xml::anonymous("<xml> <a><b><e>NO1</e><c>A</c><c>B</c><c>C</c></b></a> </xml>");
eq('C', $x->find_get('a/b/c', 2)->value());
$i = 0;
foreach ($x->find('a/b/c') as $f) {
    $i++;
}
eq(3, $i);
Esempio n. 8
0
 public static function mail_template_list()
 {
     $path = \ebi\Conf::get(\ebi\Mail::class . '@resource_path', \ebi\Conf::resource_path('mail'));
     $template_list = [];
     try {
         foreach (\ebi\Util::ls($path, true, '/\\.xml$/') as $f) {
             $info = new \ebi\Dt\DocInfo();
             $info->name(str_replace(\ebi\Util::path_slash($path, null, true), '', $f->getPathname()));
             try {
                 $xml = \ebi\Xml::extract(file_get_contents($f->getPathname()), 'mail');
                 $info->document($xml->find_get('subject')->value());
                 $info->set_opt('x_t_code', \ebi\Mail::xtc($info->name()));
                 $template_list[] = $info;
             } catch (\ebi\exception\NotFoundException $e) {
             }
         }
     } catch (\ebi\exception\InvalidArgumentException $e) {
     }
     return $template_list;
 }
Esempio n. 9
0
 /**
  * bodyをXMLとして解析しXMLオブジェクトとして返す
  * @return \ebi\Xml
  */
 public function xml($name = null)
 {
     return \ebi\Xml::extract($this->body(), $name);
 }
Esempio n. 10
0
 private function html_list($src)
 {
     if (preg_match_all('/<(table|ul|ol)\\s[^>]*rt\\:/i', $src, $m, PREG_OFFSET_CAPTURE)) {
         $tags = [];
         foreach ($m[1] as $v) {
             try {
                 $tags[] = \ebi\Xml::extract(substr($src, $v[1] - 1), $v[0]);
             } catch (\ebi\exception\NotFoundException $e) {
             }
         }
         foreach ($tags as $obj) {
             $obj->escape(false);
             $name = strtolower($obj->name());
             $param = $obj->in_attr('rt:param');
             $value = sprintf('<rt:loop param="%s" var="%s" counter="%s" ' . 'key="%s" ' . '>', $param, $obj->in_attr('rt:var', 'loop_var'), $obj->in_attr('rt:counter', 'loop_counter'), $obj->in_attr('rt:key', 'loop_key'));
             $rawvalue = $obj->value();
             if ($name == 'table') {
                 try {
                     $t = \ebi\Xml::extract($rawvalue, 'tbody');
                     $t->escape(false);
                     $t->value($value . $t->value() . '</rt:loop>');
                     $value = str_replace($t->plain(), $t->get(), $rawvalue);
                 } catch (\ebi\exception\NotFoundException $e) {
                     $value = $value . $rawvalue . '</rt:loop>';
                 }
             } else {
                 $value = $value . $rawvalue . '</rt:loop>';
             }
             $obj->value($this->html_list($value));
             $obj->rm_attr('rt:param', 'rt:key', 'rt:var', 'rt:counter');
             $src = str_replace($obj->plain(), $obj->get(), $src);
         }
     }
     return $src;
 }
Esempio n. 11
0
 private function before_exhtml($src)
 {
     return \ebi\Xml::find_replace($src, 'pre|cli|tree', function ($xml) {
         $plain = $xml->plain();
         $tag = strtolower($xml->name());
         $xml->escape(false);
         $caption = $xml->in_attr('caption');
         $xml->rm_attr('caption');
         $style = $xml->in_attr('style');
         if ($tag == 'cli') {
             $xml->name('pre');
             $xml->attr('style', 'background-color:#fff; color:#000; border-color:#000; padding:5px;' . $style);
         } else {
             if ($tag == 'tree') {
                 $xml->name('pre');
                 $xml->attr('style', 'padding: 5px; line-height: 20px;' . $style);
                 $xml->attr('class', 'prettyprint lang-c');
             } else {
                 $xml->attr('class', 'prettyprint');
             }
         }
         if (empty($caption)) {
             $xml->attr('style', 'margin-top: 20px; ' . $xml->in_attr('style'));
         }
         $value = $xml->value();
         $value = preg_replace("/<(rt:.+?)>/ms", "&lt;\\1&gt;", $value);
         $value = str_replace(['<php>', '</php>'], ['<?php', '?>'], $value);
         $value = $this->pre($value);
         if (empty($value)) {
             $value = PHP_EOL;
         }
         if ($tag == 'tree') {
             $tree = [];
             $len = 0;
             $v = '';
             foreach (explode("\n", $value) as $k => $line) {
                 if (preg_match("/^(\\s*)([\\.\\w\\{\\}\\[\\]\\(\\)]+)[:]{0,1}(.*)\$/", $line, $m)) {
                     $tree[$k] = [strlen(str_replace("\t", ' ', $m[1])), trim($m[2]), trim($m[3])];
                     $tree[$k][3] = strlen($tree[$k][1]);
                     if ($len < $tree[$k][3] + $tree[$k][0]) {
                         $len = $tree[$k][3] + $tree[$k][0];
                     }
                 }
             }
             if (!empty($caption)) {
                 $v = $caption . PHP_EOL;
             }
             $v .= '.' . PHP_EOL;
             $last = sizeof($tree) - 1;
             foreach ($tree as $k => $t) {
                 $v .= str_repeat('| ', $t[0]);
                 $v .= $t[0] > 0 && isset($tree[$k + 1]) && $tree[$k + 1][0] < $t[0] || $k == $last ? '`' : '|';
                 $v .= '-- ' . $t[1] . str_repeat(' ', $len - $t[3] - $t[0] * 2 + 4) . (empty($t[2]) ? '' : ' .. ') . $t[2] . PHP_EOL;
             }
             $xml->value($v);
             $plain = $xml->get();
         } else {
             $format = $xml->in_attr('format');
             $xml->rm_attr('format');
             if ($format == 'plain') {
                 $plain = $xml->get();
             } else {
                 $value = str_replace("\t", "&nbsp;&nbsp;", $value);
                 $value = str_replace(['<', '>', '\'', '"'], ['&lt;', '&gt;', '&#039;', '&quot;'], $value);
                 $xml->value($value);
                 $plain = str_replace(['$', '='], ['__RTD__', '__RTE__'], $xml->get());
             }
             if (!empty($caption)) {
                 $plain = '<div style="margin-top:20px; color:#7a43b6; font-weight: bold;">' . $caption . '</div>' . $plain;
             }
         }
     });
 }
Esempio n. 12
0
$tag = \ebi\Xml::extract($src, 'tag');
eq("hoge", $tag->find_get("abc/def/ghi")->value());
eq("123", $tag->find_get("abc/def")->in_attr('var'));
eq("selected", $tag->find_get("abc/def/ghi")->in_attr('selected'));
eq("<def var='123'><ghi selected>hoge</ghi></def>", $tag->find_get("abc/def")->plain());
try {
    $tag->find_get("abc/def/xyz");
    fail();
} catch (\ebi\exception\NotFoundException $e) {
}
$src = <<<'PRE'
<tag>
<abc>
<def var="123">
<ghi selected>hoge</ghi>
<ghi>
<jkl>rails</jkl>
</ghi>
<ghi ab="true">django</ghi>
</def>
</abc>
</tag>
PRE;
$tag = \ebi\Xml::extract($src, "tag");
eq("django", $tag->find_get("abc/def/ghi", 2)->value());
eq("rails", $tag->find_get("abc/def/ghi", 1)->find_get('jkl')->value());
eq("123", $tag->find_get("abc/def")->in_attr('var'));
eq("true", $tag->find_get("abc/def/ghi", 2)->in_attr('ab'));
eq('selected', $tag->find_get("abc/def/ghi")->in_attr('selected'));
eq(null, $tag->find_get("abc/def/ghi", 1)->in_attr('selected'));
eq([], $tag->find_get("abc/def")->find('xyz'));
Esempio n. 13
0
<?php

$src = <<<XML
<aaa><bbb></bbb><ccc>CCC</ccc><ddd></ddd><eee><FFF>aa</FFF><GGG></GGG></eee><fff /><ggg /></aaa>
XML;
$xml = <<<XML
<aaa>
\t<bbb></bbb>
\t<ccc>CCC</ccc>
\t<ddd></ddd>
\t<eee>
\t\t<FFF>aa</FFF>
\t\t<GGG></GGG>
\t</eee>
\t<fff />
\t<ggg />
</aaa>

XML;
$f = \ebi\Xml::format($src);
eq($xml, $f);
Esempio n. 14
0
 /**
  * $srcから対象のXMLをすべて置換した文字列を返す
  * @param string $src
  * @param string $name
  * @param callable $func
  * @return string
  */
 public static function find_replace_all($src, $name, $func)
 {
     try {
         if (!is_callable($func)) {
             throw new \ebi\exception\InvalidArgumentException('invalid function');
         }
         $i = 0;
         while (true) {
             $xml = \ebi\Xml::extract($src, $name);
             $replace = call_user_func_array($func, [$xml]);
             if (!is_null($replace)) {
                 $src = str_replace($xml->plain(), $replace instanceof self ? $replace->get() : $replace, $src);
             }
             if ($i++ > 100) {
                 throw new \ebi\exception\RetryLimitOverException('Maximum function nesting level of ’100');
             }
         }
     } catch (\ebi\exception\NotFoundException $e) {
     }
     return $src;
 }
Esempio n. 15
0
 public function before_template($src)
 {
     return \ebi\Xml::find_replace_all($src, 'rt:invalid', function ($xml) {
         $param = $xml->in_attr('param');
         $type = $xml->in_attr('type');
         $var = $xml->in_attr('var', 'rtinvalid_var' . uniqid(''));
         if (!isset($param[0]) || $param[0] !== '$') {
             $param = '"' . $param . '"';
         }
         if (!isset($type[0]) || $type[0] !== '$') {
             $type = '"' . $type . '"';
         }
         $value = $xml->value();
         $tagtype = $xml->in_attr('tag');
         if (empty($value)) {
             $varnm = 'rtinvalid_varnm' . uniqid('');
             $value = sprintf('<div class="%s"><ul><rt:loop param="%s" var="%s">' . PHP_EOL . '<li>{$%s.getMessage()}</li>' . '</rt:loop></ul></div>', $xml->in_attr('class', 'alert alert-danger'), $var, $varnm, $varnm, empty($tagtype) ? '' : '</' . $tagtype . '>');
         }
         return sprintf("<?php if(\\ebi\\FlowInvalid::has(%s,%s)){ ?>" . "<?php \$%s = \\ebi\\FlowInvalid::get(%s,%s); ?>" . preg_replace("/<rt\\:else[\\s]*.*?>/i", "<?php }else{ ?>", $value) . "<?php } ?>", $param, $type, $var, $param, $type);
     });
 }
Esempio n. 16
0
<?php

$xml = \ebi\Xml::extract('<asd><abc><def><aa>AA</aa><bb>BB</bb><cc>CC</cc></def></abc></asd>');
eq('<asd><abc><def><aa>AA</aa><bb>ZZ</bb><cc>CC</cc></def></abc></asd>', $xml->replace('def/bb', 'ZZ')->get());
eq('<asd><abc><def><aa>AA</aa><bb>BB</bb><cc>CC</cc></def></abc></asd>', $xml->get());
$xml = \ebi\Xml::extract('<asd><abc><def><aa>AA</aa><bb>BB</bb><cc>CC</cc></def></abc></asd>');
eq('<asd><abc><def>ZZ</def></abc></asd>', $xml->replace('def', 'ZZ')->get());
$xml = \ebi\Xml::extract('<asd><abc><def><aa>AA</aa><bb>BB</bb><cc>CC</cc><dd><aaa>AAA</aaa><bbb>BBB</bbb><ccc>CCC</ccc></dd></def></abc></asd>');
eq('<asd><abc><def><aa>AA</aa><bb>BB</bb><cc>CC</cc><dd><aaa>AAA</aaa><bbb>ZZZ</bbb><ccc>CCC</ccc></dd></def></abc></asd>', $xml->replace('def/dd/bbb', 'ZZZ')->get());