prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [WIP] fix xmliter namespace on selected node
  This PR was triggered by [scrapy-users](https://groups.google.com/forum/#!topic/scrapy-users/VN6409UHexQ)
  
  Actually `xmliter` populates a `Selector` with everything from the position 0 to the tag start, so if we had 100mb before the tag we want to iter it copy those 100mb across all the `Selector` objects. Also it just extract this info for the first tag and embed the rest on that, this can cause info crossing.
  
  In this PR I kept the regex stuff even tho I think we should use something like [`iterparse`](https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse).
  
  Currently `xmliter_lxml` tests are failing due to it has a different API.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `scrapy/utils/iterators.py`
  Content:
  ```
  1 import csv
  2 import logging
  3 import re
  4 from io import StringIO
  5 
  6 from scrapy.http import TextResponse, Response
  7 from scrapy.selector import Selector
  8 from scrapy.utils.python import re_rsearch, to_unicode
  9 
  10 
  11 logger = logging.getLogger(__name__)
  12 
  13 
  14 def xmliter(obj, nodename):
  15     """Return a iterator of Selector's over all nodes of a XML document,
  16        given the name of the node to iterate. Useful for parsing XML feeds.
  17 
  18     obj can be:
  19     - a Response object
  20     - a unicode string
  21     - a string encoded as utf-8
  22     """
  23     nodename_patt = re.escape(nodename)
  24 
  25     HEADER_START_RE = re.compile(fr'^(.*?)<\s*{nodename_patt}(?:\s|>)', re.S)
  26     HEADER_END_RE = re.compile(fr'<\s*/{nodename_patt}\s*>', re.S)
  27     text = _body_or_str(obj)
  28 
  29     header_start = re.search(HEADER_START_RE, text)
  30     header_start = header_start.group(1).strip() if header_start else ''
  31     header_end = re_rsearch(HEADER_END_RE, text)
  32     header_end = text[header_end[1]:].strip() if header_end else ''
  33 
  34     r = re.compile(fr'<{nodename_patt}[\s>].*?</{nodename_patt}>', re.DOTALL)
  35     for match in r.finditer(text):
  36         nodetext = header_start + match.group() + header_end
  37         yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]
  38 
  39 
  40 def xmliter_lxml(obj, nodename, namespace=None, prefix='x'):
  41     from lxml import etree
  42     reader = _StreamReader(obj)
  43     tag = f'{{{namespace}}}{nodename}'if namespace else nodename
  44     iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)
  45     selxpath = '//' + (f'{prefix}:{nodename}' if namespace else nodename)
  46     for _, node in iterable:
  47         nodetext = etree.tostring(node, encoding='unicode')
  48         node.clear()
  49         xs = Selector(text=nodetext, type='xml')
  50         if namespace:
  51             xs.register_namespace(prefix, namespace)
  52         yield xs.xpath(selxpath)[0]
  53 
  54 
  55 class _StreamReader:
  56 
  57     def __init__(self, obj):
  58         self._ptr = 0
  59         if isinstance(obj, Response):
  60             self._text, self.encoding = obj.body, obj.encoding
  61         else:
  62             self._text, self.encoding = obj, 'utf-8'
  63         self._is_unicode = isinstance(self._text, str)
  64 
  65     def read(self, n=65535):
  66         self.read = self._read_unicode if self._is_unicode else self._read_string
  67         return self.read(n).lstrip()
  68 
  69     def _read_string(self, n=65535):
  70         s, e = self._ptr, self._ptr + n
  71         self._ptr = e
  72         return self._text[s:e]
  73 
  74     def _read_unicode(self, n=65535):
  75         s, e = self._ptr, self._ptr + n
  76         self._ptr = e
  77         return self._text[s:e].encode('utf-8')
  78 
  79 
  80 def csviter(obj, delimiter=None, headers=None, encoding=None, quotechar=None):
  81     """ Returns an iterator of dictionaries from the given csv object
  82 
  83     obj can be:
  84     - a Response object
  85     - a unicode string
  86     - a string encoded as utf-8
  87 
  88     delimiter is the character used to separate fields on the given obj.
  89 
  90     headers is an iterable that when provided offers the keys
  91     for the returned dictionaries, if not the first row is used.
  92 
  93     quotechar is the character used to enclosure fields on the given obj.
  94     """
  95 
  96     encoding = obj.encoding if isinstance(obj, TextResponse) else encoding or 'utf-8'
  97 
  98     def row_to_unicode(row_):
  99         return [to_unicode(field, encoding) for field in row_]
  100 
  101     lines = StringIO(_body_or_str(obj, unicode=True))
  102 
  103     kwargs = {}
  104     if delimiter:
  105         kwargs["delimiter"] = delimiter
  106     if quotechar:
  107         kwargs["quotechar"] = quotechar
  108     csv_r = csv.reader(lines, **kwargs)
  109 
  110     if not headers:
  111         try:
  112             row = next(csv_r)
  113         except StopIteration:
  114             return
  115         headers = row_to_unicode(row)
  116 
  117     for row in csv_r:
  118         row = row_to_unicode(row)
  119         if len(row) != len(headers):
  120             logger.warning("ignoring row %(csvlnum)d (length: %(csvrow)d, "
  121                            "should be: %(csvheader)d)",
  122                            {'csvlnum': csv_r.line_num, 'csvrow': len(row),
  123                             'csvheader': len(headers)})
  124             continue
  125         else:
  126             yield dict(zip(headers, row))
  127 
  128 
  129 def _body_or_str(obj, unicode=True):
  130     expected_types = (Response, str, bytes)
  131     if not isinstance(obj, expected_types):
  132         expected_types_str = " or ".join(t.__name__ for t in expected_types)
  133         raise TypeError(
  134             f"Object {obj!r} must be {expected_types_str}, not {type(obj).__name__}"
  135         )
  136     if isinstance(obj, Response):
  137         if not unicode:
  138             return obj.body
  139         elif isinstance(obj, TextResponse):
  140             return obj.text
  141         else:
  142             return obj.body.decode('utf-8')
  143     elif isinstance(obj, str):
  144         return obj if unicode else obj.encode('utf-8')
  145     else:
  146         return obj.decode('utf-8') if unicode else obj
  147
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/scrapy/utils/iterators.py b/scrapy/utils/iterators.py
  --- a/scrapy/utils/iterators.py
  +++ b/scrapy/utils/iterators.py
  @@ -22,25 +22,41 @@
       """
       nodename_patt = re.escape(nodename)
   
  -    HEADER_START_RE = re.compile(fr'^(.*?)<\s*{nodename_patt}(?:\s|>)', re.S)
  +    DOCUMENT_HEADER_RE = re.compile(r'<\?xml[^>]+>\s*', re.S)
       HEADER_END_RE = re.compile(fr'<\s*/{nodename_patt}\s*>', re.S)
  +    END_TAG_RE = re.compile(r'<\s*/([^\s>]+)\s*>', re.S)
  +    NAMESPACE_RE = re.compile(r'((xmlns[:A-Za-z]*)=[^>\s]+)', re.S)
       text = _body_or_str(obj)
   
  -    header_start = re.search(HEADER_START_RE, text)
  -    header_start = header_start.group(1).strip() if header_start else ''
  -    header_end = re_rsearch(HEADER_END_RE, text)
  -    header_end = text[header_end[1]:].strip() if header_end else ''
  +    document_header = re.search(DOCUMENT_HEADER_RE, text)
  +    document_header = document_header.group().strip() if document_header else ''
  +    header_end_idx = re_rsearch(HEADER_END_RE, text)
  +    header_end = text[header_end_idx[1]:].strip() if header_end_idx else ''
  +    namespaces = {}
  +    if header_end:
  +        for tagname in reversed(re.findall(END_TAG_RE, header_end)):
  +            tag = re.search(fr'<\s*{tagname}.*?xmlns[:=][^>]*>', text[:header_end_idx[1]], re.S)
  +            if tag:
  +                namespaces.update(reversed(x) for x in re.findall(NAMESPACE_RE, tag.group()))
   
       r = re.compile(fr'<{nodename_patt}[\s>].*?</{nodename_patt}>', re.DOTALL)
       for match in r.finditer(text):
  -        nodetext = header_start + match.group() + header_end
  -        yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]
  +        nodetext = (
  +            document_header
  +            + match.group().replace(
  +                nodename,
  +                f'{nodename} {" ".join(namespaces.values())}',
  +                1
  +            )
  +            + header_end
  +        )
  +        yield Selector(text=nodetext, type='xml')
   
   
   def xmliter_lxml(obj, nodename, namespace=None, prefix='x'):
       from lxml import etree
       reader = _StreamReader(obj)
  -    tag = f'{{{namespace}}}{nodename}'if namespace else nodename
  +    tag = f'{{{namespace}}}{nodename}' if namespace else nodename
       iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)
       selxpath = '//' + (f'{prefix}:{nodename}' if namespace else nodename)
       for _, node in iterable:
  
verification_info: {"golden_diff": "diff --git a/scrapy/utils/iterators.py b/scrapy/utils/iterators.py\n--- a/scrapy/utils/iterators.py\n+++ b/scrapy/utils/iterators.py\n@@ -22,25 +22,41 @@\n     \"\"\"\n     nodename_patt = re.escape(nodename)\n \n-    HEADER_START_RE = re.compile(fr'^(.*?)<\\s*{nodename_patt}(?:\\s|>)', re.S)\n+    DOCUMENT_HEADER_RE = re.compile(r'<\\?xml[^>]+>\\s*', re.S)\n     HEADER_END_RE = re.compile(fr'<\\s*/{nodename_patt}\\s*>', re.S)\n+    END_TAG_RE = re.compile(r'<\\s*/([^\\s>]+)\\s*>', re.S)\n+    NAMESPACE_RE = re.compile(r'((xmlns[:A-Za-z]*)=[^>\\s]+)', re.S)\n     text = _body_or_str(obj)\n \n-    header_start = re.search(HEADER_START_RE, text)\n-    header_start = header_start.group(1).strip() if header_start else ''\n-    header_end = re_rsearch(HEADER_END_RE, text)\n-    header_end = text[header_end[1]:].strip() if header_end else ''\n+    document_header = re.search(DOCUMENT_HEADER_RE, text)\n+    document_header = document_header.group().strip() if document_header else ''\n+    header_end_idx = re_rsearch(HEADER_END_RE, text)\n+    header_end = text[header_end_idx[1]:].strip() if header_end_idx else ''\n+    namespaces = {}\n+    if header_end:\n+        for tagname in reversed(re.findall(END_TAG_RE, header_end)):\n+            tag = re.search(fr'<\\s*{tagname}.*?xmlns[:=][^>]*>', text[:header_end_idx[1]], re.S)\n+            if tag:\n+                namespaces.update(reversed(x) for x in re.findall(NAMESPACE_RE, tag.group()))\n \n     r = re.compile(fr'<{nodename_patt}[\\s>].*?</{nodename_patt}>', re.DOTALL)\n     for match in r.finditer(text):\n-        nodetext = header_start + match.group() + header_end\n-        yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]\n+        nodetext = (\n+            document_header\n+            + match.group().replace(\n+                nodename,\n+                f'{nodename} {\" \".join(namespaces.values())}',\n+                1\n+            )\n+            + header_end\n+        )\n+        yield Selector(text=nodetext, type='xml')\n \n \n def xmliter_lxml(obj, nodename, namespace=None, prefix='x'):\n     from lxml import etree\n     reader = _StreamReader(obj)\n-    tag = f'{{{namespace}}}{nodename}'if namespace else nodename\n+    tag = f'{{{namespace}}}{nodename}' if namespace else nodename\n     iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)\n     selxpath = '//' + (f'{prefix}:{nodename}' if namespace else nodename)\n     for _, node in iterable:\n", "issue": "[WIP] fix xmliter namespace on selected node\nThis PR was triggered by [scrapy-users](https://groups.google.com/forum/#!topic/scrapy-users/VN6409UHexQ)\n\nActually `xmliter` populates a `Selector` with everything from the position 0 to the tag start, so if we had 100mb before the tag we want to iter it copy those 100mb across all the `Selector` objects. Also it just extract this info for the first tag and embed the rest on that, this can cause info crossing.\n\nIn this PR I kept the regex stuff even tho I think we should use something like [`iterparse`](https://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.iterparse).\n\nCurrently `xmliter_lxml` tests are failing due to it has a different API.\n\n", "before_files": [{"content": "import csv\nimport logging\nimport re\nfrom io import StringIO\n\nfrom scrapy.http import TextResponse, Response\nfrom scrapy.selector import Selector\nfrom scrapy.utils.python import re_rsearch, to_unicode\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef xmliter(obj, nodename):\n    \"\"\"Return a iterator of Selector's over all nodes of a XML document,\n       given the name of the node to iterate. Useful for parsing XML feeds.\n\n    obj can be:\n    - a Response object\n    - a unicode string\n    - a string encoded as utf-8\n    \"\"\"\n    nodename_patt = re.escape(nodename)\n\n    HEADER_START_RE = re.compile(fr'^(.*?)<\\s*{nodename_patt}(?:\\s|>)', re.S)\n    HEADER_END_RE = re.compile(fr'<\\s*/{nodename_patt}\\s*>', re.S)\n    text = _body_or_str(obj)\n\n    header_start = re.search(HEADER_START_RE, text)\n    header_start = header_start.group(1).strip() if header_start else ''\n    header_end = re_rsearch(HEADER_END_RE, text)\n    header_end = text[header_end[1]:].strip() if header_end else ''\n\n    r = re.compile(fr'<{nodename_patt}[\\s>].*?</{nodename_patt}>', re.DOTALL)\n    for match in r.finditer(text):\n        nodetext = header_start + match.group() + header_end\n        yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]\n\n\ndef xmliter_lxml(obj, nodename, namespace=None, prefix='x'):\n    from lxml import etree\n    reader = _StreamReader(obj)\n    tag = f'{{{namespace}}}{nodename}'if namespace else nodename\n    iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)\n    selxpath = '//' + (f'{prefix}:{nodename}' if namespace else nodename)\n    for _, node in iterable:\n        nodetext = etree.tostring(node, encoding='unicode')\n        node.clear()\n        xs = Selector(text=nodetext, type='xml')\n        if namespace:\n            xs.register_namespace(prefix, namespace)\n        yield xs.xpath(selxpath)[0]\n\n\nclass _StreamReader:\n\n    def __init__(self, obj):\n        self._ptr = 0\n        if isinstance(obj, Response):\n            self._text, self.encoding = obj.body, obj.encoding\n        else:\n            self._text, self.encoding = obj, 'utf-8'\n        self._is_unicode = isinstance(self._text, str)\n\n    def read(self, n=65535):\n        self.read = self._read_unicode if self._is_unicode else self._read_string\n        return self.read(n).lstrip()\n\n    def _read_string(self, n=65535):\n        s, e = self._ptr, self._ptr + n\n        self._ptr = e\n        return self._text[s:e]\n\n    def _read_unicode(self, n=65535):\n        s, e = self._ptr, self._ptr + n\n        self._ptr = e\n        return self._text[s:e].encode('utf-8')\n\n\ndef csviter(obj, delimiter=None, headers=None, encoding=None, quotechar=None):\n    \"\"\" Returns an iterator of dictionaries from the given csv object\n\n    obj can be:\n    - a Response object\n    - a unicode string\n    - a string encoded as utf-8\n\n    delimiter is the character used to separate fields on the given obj.\n\n    headers is an iterable that when provided offers the keys\n    for the returned dictionaries, if not the first row is used.\n\n    quotechar is the character used to enclosure fields on the given obj.\n    \"\"\"\n\n    encoding = obj.encoding if isinstance(obj, TextResponse) else encoding or 'utf-8'\n\n    def row_to_unicode(row_):\n        return [to_unicode(field, encoding) for field in row_]\n\n    lines = StringIO(_body_or_str(obj, unicode=True))\n\n    kwargs = {}\n    if delimiter:\n        kwargs[\"delimiter\"] = delimiter\n    if quotechar:\n        kwargs[\"quotechar\"] = quotechar\n    csv_r = csv.reader(lines, **kwargs)\n\n    if not headers:\n        try:\n            row = next(csv_r)\n        except StopIteration:\n            return\n        headers = row_to_unicode(row)\n\n    for row in csv_r:\n        row = row_to_unicode(row)\n        if len(row) != len(headers):\n            logger.warning(\"ignoring row %(csvlnum)d (length: %(csvrow)d, \"\n                           \"should be: %(csvheader)d)\",\n                           {'csvlnum': csv_r.line_num, 'csvrow': len(row),\n                            'csvheader': len(headers)})\n            continue\n        else:\n            yield dict(zip(headers, row))\n\n\ndef _body_or_str(obj, unicode=True):\n    expected_types = (Response, str, bytes)\n    if not isinstance(obj, expected_types):\n        expected_types_str = \" or \".join(t.__name__ for t in expected_types)\n        raise TypeError(\n            f\"Object {obj!r} must be {expected_types_str}, not {type(obj).__name__}\"\n        )\n    if isinstance(obj, Response):\n        if not unicode:\n            return obj.body\n        elif isinstance(obj, TextResponse):\n            return obj.text\n        else:\n            return obj.body.decode('utf-8')\n    elif isinstance(obj, str):\n        return obj if unicode else obj.encode('utf-8')\n    else:\n        return obj.decode('utf-8') if unicode else obj\n", "path": "scrapy/utils/iterators.py"}], "after_files": [{"content": "import csv\nimport logging\nimport re\nfrom io import StringIO\n\nfrom scrapy.http import TextResponse, Response\nfrom scrapy.selector import Selector\nfrom scrapy.utils.python import re_rsearch, to_unicode\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef xmliter(obj, nodename):\n    \"\"\"Return a iterator of Selector's over all nodes of a XML document,\n       given the name of the node to iterate. Useful for parsing XML feeds.\n\n    obj can be:\n    - a Response object\n    - a unicode string\n    - a string encoded as utf-8\n    \"\"\"\n    nodename_patt = re.escape(nodename)\n\n    DOCUMENT_HEADER_RE = re.compile(r'<\\?xml[^>]+>\\s*', re.S)\n    HEADER_END_RE = re.compile(fr'<\\s*/{nodename_patt}\\s*>', re.S)\n    END_TAG_RE = re.compile(r'<\\s*/([^\\s>]+)\\s*>', re.S)\n    NAMESPACE_RE = re.compile(r'((xmlns[:A-Za-z]*)=[^>\\s]+)', re.S)\n    text = _body_or_str(obj)\n\n    document_header = re.search(DOCUMENT_HEADER_RE, text)\n    document_header = document_header.group().strip() if document_header else ''\n    header_end_idx = re_rsearch(HEADER_END_RE, text)\n    header_end = text[header_end_idx[1]:].strip() if header_end_idx else ''\n    namespaces = {}\n    if header_end:\n        for tagname in reversed(re.findall(END_TAG_RE, header_end)):\n            tag = re.search(fr'<\\s*{tagname}.*?xmlns[:=][^>]*>', text[:header_end_idx[1]], re.S)\n            if tag:\n                namespaces.update(reversed(x) for x in re.findall(NAMESPACE_RE, tag.group()))\n\n    r = re.compile(fr'<{nodename_patt}[\\s>].*?</{nodename_patt}>', re.DOTALL)\n    for match in r.finditer(text):\n        nodetext = (\n            document_header\n            + match.group().replace(\n                nodename,\n                f'{nodename} {\" \".join(namespaces.values())}',\n                1\n            )\n            + header_end\n        )\n        yield Selector(text=nodetext, type='xml')\n\n\ndef xmliter_lxml(obj, nodename, namespace=None, prefix='x'):\n    from lxml import etree\n    reader = _StreamReader(obj)\n    tag = f'{{{namespace}}}{nodename}' if namespace else nodename\n    iterable = etree.iterparse(reader, tag=tag, encoding=reader.encoding)\n    selxpath = '//' + (f'{prefix}:{nodename}' if namespace else nodename)\n    for _, node in iterable:\n        nodetext = etree.tostring(node, encoding='unicode')\n        node.clear()\n        xs = Selector(text=nodetext, type='xml')\n        if namespace:\n            xs.register_namespace(prefix, namespace)\n        yield xs.xpath(selxpath)[0]\n\n\nclass _StreamReader:\n\n    def __init__(self, obj):\n        self._ptr = 0\n        if isinstance(obj, Response):\n            self._text, self.encoding = obj.body, obj.encoding\n        else:\n            self._text, self.encoding = obj, 'utf-8'\n        self._is_unicode = isinstance(self._text, str)\n\n    def read(self, n=65535):\n        self.read = self._read_unicode if self._is_unicode else self._read_string\n        return self.read(n).lstrip()\n\n    def _read_string(self, n=65535):\n        s, e = self._ptr, self._ptr + n\n        self._ptr = e\n        return self._text[s:e]\n\n    def _read_unicode(self, n=65535):\n        s, e = self._ptr, self._ptr + n\n        self._ptr = e\n        return self._text[s:e].encode('utf-8')\n\n\ndef csviter(obj, delimiter=None, headers=None, encoding=None, quotechar=None):\n    \"\"\" Returns an iterator of dictionaries from the given csv object\n\n    obj can be:\n    - a Response object\n    - a unicode string\n    - a string encoded as utf-8\n\n    delimiter is the character used to separate fields on the given obj.\n\n    headers is an iterable that when provided offers the keys\n    for the returned dictionaries, if not the first row is used.\n\n    quotechar is the character used to enclosure fields on the given obj.\n    \"\"\"\n\n    encoding = obj.encoding if isinstance(obj, TextResponse) else encoding or 'utf-8'\n\n    def row_to_unicode(row_):\n        return [to_unicode(field, encoding) for field in row_]\n\n    lines = StringIO(_body_or_str(obj, unicode=True))\n\n    kwargs = {}\n    if delimiter:\n        kwargs[\"delimiter\"] = delimiter\n    if quotechar:\n        kwargs[\"quotechar\"] = quotechar\n    csv_r = csv.reader(lines, **kwargs)\n\n    if not headers:\n        try:\n            row = next(csv_r)\n        except StopIteration:\n            return\n        headers = row_to_unicode(row)\n\n    for row in csv_r:\n        row = row_to_unicode(row)\n        if len(row) != len(headers):\n            logger.warning(\"ignoring row %(csvlnum)d (length: %(csvrow)d, \"\n                           \"should be: %(csvheader)d)\",\n                           {'csvlnum': csv_r.line_num, 'csvrow': len(row),\n                            'csvheader': len(headers)})\n            continue\n        else:\n            yield dict(zip(headers, row))\n\n\ndef _body_or_str(obj, unicode=True):\n    expected_types = (Response, str, bytes)\n    if not isinstance(obj, expected_types):\n        expected_types_str = \" or \".join(t.__name__ for t in expected_types)\n        raise TypeError(\n            f\"Object {obj!r} must be {expected_types_str}, not {type(obj).__name__}\"\n        )\n    if isinstance(obj, Response):\n        if not unicode:\n            return obj.body\n        elif isinstance(obj, TextResponse):\n            return obj.text\n        else:\n            return obj.body.decode('utf-8')\n    elif isinstance(obj, str):\n        return obj if unicode else obj.encode('utf-8')\n    else:\n        return obj.decode('utf-8') if unicode else obj\n", "path": "scrapy/utils/iterators.py"}]}