codecov-io: ## [Current coverage][1] is `100.00%`
> Merging **#33** into **master** will not affect coverage as of [`13e366f`][3]


```diff
@@            master     #33   diff @@
======================================
  Files            7       7       
  Stmts          348     351     +3
  Branches        36      38     +2
  Methods          0       0       
======================================
+ Hit            348     351     +3
  Partial          0       0       
  Missed           0       0       
```

> Review entire [Coverage Diff][4] as of [`13e366f`][3]


[1]: https://codecov.io/github/Stranger6667/pyanyapi?ref=13e366f7c2915fc8f7f7e7c1396ac9772f6942e8
[2]: https://codecov.io/github/Stranger6667/pyanyapi/features/suggestions?ref=13e366f7c2915fc8f7f7e7c1396ac9772f6942e8
[3]: https://codecov.io/github/Stranger6667/pyanyapi/commit/13e366f7c2915fc8f7f7e7c1396ac9772f6942e8
[4]: https://codecov.io/github/Stranger6667/pyanyapi/compare/b1f0bc477bb850dc39c4646ff359e59d764a9f77...13e366f7c2915fc8f7f7e7c1396ac9772f6942e8

> Powered by [Codecov](https://codecov.io). Updated on successful CI builds.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 016a9b7..ecfdb61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@ History
 ----------------
 
 * Fixed `lxml` installation on PyPy (#34).
+* Add support for subparsers (#32).
 
 0.5.3 - 30.10.2015
 ----------------
diff --git a/README.rst b/README.rst
index ad508c4..7600418 100644
--- a/README.rst
+++ b/README.rst
@@ -105,6 +105,36 @@ list. Here comes "base-children" setup style.
     >>> api.test
     ['123 ', ' 234']
 
+There is another option to interact with sub-elements. Sub parsers!
+
+.. code:: python
+
+    from pyanyapi import HTMLParser
+
+
+    class SubParser(HTMLParser):
+        settings = {
+            'href': 'string(//@href)',
+            'text': 'string(//text())'
+        }
+
+
+    class Parser(HTMLParser):
+        settings = {
+            'elem': {
+                'base': './/a',
+                'parser': SubParser
+            }
+        }
+
+    >>> api = Parser().parse('<html><body><a href='#test'>test</body></html>')
+    >>> api.elem[0].href
+    #test
+    >>> api.elem[0].text
+    test
+
+Also you can pass sub parsers as classes or like instances.
+
 Settings inheritance
 ~~~~~~~~~~~~~~~~~~~~
 
diff --git a/pyanyapi/interfaces.py b/pyanyapi/interfaces.py
index 121f684..53734a7 100644
--- a/pyanyapi/interfaces.py
+++ b/pyanyapi/interfaces.py
@@ -141,6 +141,12 @@ class XPathInterface(BaseInterface):
             child_query = settings.get('children')
             if child_query:
                 return [self.maybe_strip(''.join(element.xpath(child_query))) for element in result]
+            sub_parser = settings.get('parser')
+            if sub_parser:
+                return [
+                    (sub_parser() if callable(sub_parser) else sub_parser).parse(etree.tostring(element))
+                    for element in result
+                ]
             return result
 
         return self.parse(settings)

Improve children syntax 
As we discussed =D

Add supporting for childrens parse for every parent element

Example settings: 
```python
class IMDBParser(HTMLParser):
    settings = {
        'films_blocks': {
            'base': '//div[@class="media"]',
            'children': {
                'title': '/h4',
                'link': '/span/a/@href'
            }
        }
    }
```
Example usage:
```
parsed_elements.film_blocks[0].title
```
or something like dictionary with childs in Element object.

diff --git a/tests/conftest.py b/tests/conftest.py
index 06f9542..d127796 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -4,7 +4,7 @@ import sys
 
 import pytest
 
-from pyanyapi import JSONParser, RegExpParser, CombinedParser, interface_property, interface_method
+from pyanyapi import JSONParser, RegExpParser, CombinedParser, interface_property, interface_method, HTMLParser
 
 
 class EmptyValuesParser(CombinedParser):
@@ -74,6 +74,13 @@ class ChildParser(ParentParser):
     }
 
 
+class SubParser(HTMLParser):
+    settings = {
+        'href': 'string(//@href)',
+        'text': 'string(//text())'
+    }
+
+
 class SimpleParser(RegExpParser):
     settings = {
         'test': '\d+.\d+',
diff --git a/tests/test_parsers.py b/tests/test_parsers.py
index e13a167..163b42c 100644
--- a/tests/test_parsers.py
+++ b/tests/test_parsers.py
@@ -4,12 +4,21 @@ import re
 import pytest
 
 from ._compat import patch
-from .conftest import ChildParser, SimpleParser, lxml_is_supported, lxml_is_not_supported
-from pyanyapi import XMLObjectifyParser, XMLParser, JSONParser, YAMLParser, RegExpParser, AJAXParser, CSVParser
+from .conftest import ChildParser, SubParser, SimpleParser, lxml_is_supported, lxml_is_not_supported
+from pyanyapi import (
+    XMLObjectifyParser,
+    XMLParser,
+    JSONParser,
+    YAMLParser,
+    RegExpParser,
+    AJAXParser,
+    CSVParser,
+    HTMLParser,
+)
 from pyanyapi.exceptions import ResponseParseError
 
 
-HTML_CONTENT = "<html><body><a href='#test'></body></html>"
+HTML_CONTENT = "<html><body><a href='#test'>test</body></html>"
 XML_CONTENT = '''<?xml version="1.0" encoding="UTF-8"?>
 <response>
 <id>32e9a4a2</id>
@@ -289,3 +298,21 @@ def test_csv_parser_error():
     parsed = CSVParser({'test': '1:1'}).parse(123)
     with pytest.raises(ResponseParseError):
         parsed.test
+
+
+@lxml_is_supported
+@pytest.mark.parametrize('sub_parser', (SubParser, SubParser()))
+def test_children(sub_parser):
+
+    class Parser(HTMLParser):
+        settings = {
+            'elem': {
+                'base': './/a',
+                'parser': sub_parser
+            }
+        }
+
+    api = Parser().parse(HTML_CONTENT)
+    sub_api = api.elem[0]
+    assert sub_api.href == '#test'
+    assert sub_api.text == 'test'

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov
3.5
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
coverage==6.2
importlib-metadata==4.8.3
iniconfig==1.1.1
lxml==5.3.1
packaging==21.3
pluggy==1.0.0
py==1.11.0
-e git+https://github.com/Stranger6667/pyanyapi.git@433dc8263c6c346d772120ad6f402714eb95c72a#egg=pyanyapi
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
PyYAML==3.11
tomli==1.2.3
typing_extensions==4.1.1
ujson==4.3.0
zipp==3.6.0

name: pyanyapi
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - coverage==6.2
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - lxml==5.3.1
      - packaging==21.3
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pyyaml==3.11
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - ujson==4.3.0
      - zipp==3.6.0
prefix: /opt/conda/envs/pyanyapi

tests/test_parsers.py::test_children[SubParser] tests/test_parsers.py::test_children[sub_parser1]
tests/test_parsers.py::test_xml_objectify_parser tests/test_parsers.py::test_xml_objectify_parser_error tests/test_parsers.py::test_xml_parser_error tests/test_parsers.py::test_yaml_parser_error tests/test_parsers.py::test_xml_parsed[settings0] tests/test_parsers.py::test_xml_parsed[settings1] tests/test_parsers.py::test_xml_simple_settings tests/test_parsers.py::test_json_parsed tests/test_parsers.py::test_multiple_parser_join tests/test_parsers.py::test_multiply_parsers_declaration tests/test_parsers.py::test_empty_values[{"container":{"test":"value"}}-test-value] tests/test_parsers.py::test_empty_values[{"container":{"test":"value"}}-second-None] tests/test_parsers.py::test_empty_values[{"container":{"fail":[1]}}-second-None] tests/test_parsers.py::test_empty_values[{"container":[[1],[],[3]]}-third-expected3] tests/test_parsers.py::test_empty_values[{"container":null}-null-None] tests/test_parsers.py::test_empty_values[{"container":[1,2]}-test-1,2] tests/test_parsers.py::test_attributes tests/test_parsers.py::test_efficient_parsing tests/test_parsers.py::test_simple_config_xml_parser tests/test_parsers.py::test_simple_config_json_parser tests/test_parsers.py::test_settings_inheritance tests/test_parsers.py::test_complex_config tests/test_parsers.py::test_json_parse tests/test_parsers.py::test_json_value_error_parse tests/test_parsers.py::test_regexp_parse tests/test_parsers.py::test_yaml_parse tests/test_parsers.py::test_ajax_parser tests/test_parsers.py::test_ajax_parser_cache tests/test_parsers.py::test_ajax_parser_invalid_settings tests/test_parsers.py::test_parse_memoization tests/test_parsers.py::test_regexp_settings tests/test_parsers.py::test_parse_all tests/test_parsers.py::test_parse_all_combined_parser tests/test_parsers.py::test_parse_csv tests/test_parsers.py::test_parse_csv_custom_delimiter tests/test_parsers.py::test_csv_parser_error
README.rst CHANGELOG.md pyanyapi/interfaces.py
README.rst CHANGELOG.md pyanyapi/interfaces.py