Don't inconsistently add XML declarations (#1227)

This commit is contained in:
Batuhan Taskaya 2021-12-14 18:15:19 +03:00 committed by GitHub
parent 4f7f59b990
commit 3db1cdba4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 45 additions and 10 deletions

View File

@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212)) - Added support for basic JSON types on `--form`/`--multipart` when using JSON only operators (`:=`/`:=@`). ([#1212](https://github.com/httpie/httpie/issues/1212))
- Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376)) - Added support for automatically enabling `--stream` when `Content-Type` is `text/event-stream`. ([#376](https://github.com/httpie/httpie/issues/376))
- Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204)) - Broken plugins will no longer crash the whole application. ([#1204](https://github.com/httpie/httpie/issues/1204))
- Fixed auto addition of XML declaration to every formatted XML response. ([#1156](https://github.com/httpie/httpie/issues/1156))
## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14) ## [2.6.0](https://github.com/httpie/httpie/compare/2.5.0...2.6.0) (2021-10-14)

View File

@ -1747,7 +1747,9 @@ Formatting has the following effects:
to the characters they represent. to the characters they represent.
- XML and XHTML data is indented. - XML and XHTML data is indented.
You can further control the applied formatting via the more granular [format options](#format-options). Please note that sometimes there might be changes made by formatters on the actual response body (e.g
collapsing empty tags on XML) but the end result will always be semantically indistinguishable. Some of
these formatting changes can be configured more granularly through [format options](#format-options).
### Format options ### Format options

View File

@ -1,4 +1,3 @@
import sys
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from ...encoding import UTF8 from ...encoding import UTF8
@ -8,27 +7,47 @@ if TYPE_CHECKING:
from xml.dom.minidom import Document from xml.dom.minidom import Document
XML_DECLARATION_OPEN = '<?xml'
XML_DECLARATION_CLOSE = '?>'
def parse_xml(data: str) -> 'Document': def parse_xml(data: str) -> 'Document':
"""Parse given XML `data` string into an appropriate :class:`~xml.dom.minidom.Document` object.""" """Parse given XML `data` string into an appropriate :class:`~xml.dom.minidom.Document` object."""
from defusedxml.minidom import parseString from defusedxml.minidom import parseString
return parseString(data) return parseString(data)
def parse_declaration(raw_body: str) -> Optional[str]:
body = raw_body.strip()
# XMLDecl ::= '<?xml' DECL_CONTENT '?>'
if body.startswith(XML_DECLARATION_OPEN):
end = body.find(XML_DECLARATION_CLOSE)
if end != -1:
return body[:end + len(XML_DECLARATION_CLOSE)]
def pretty_xml(document: 'Document', def pretty_xml(document: 'Document',
declaration: Optional[str] = None,
encoding: Optional[str] = UTF8, encoding: Optional[str] = UTF8,
indent: int = 2, indent: int = 2) -> str:
standalone: Optional[bool] = None) -> str:
"""Render the given :class:`~xml.dom.minidom.Document` `document` into a prettified string.""" """Render the given :class:`~xml.dom.minidom.Document` `document` into a prettified string."""
kwargs = { kwargs = {
'encoding': encoding or UTF8, 'encoding': encoding or UTF8,
'indent': ' ' * indent, 'indent': ' ' * indent,
} }
if standalone is not None and sys.version_info >= (3, 9):
kwargs['standalone'] = standalone
body = document.toprettyxml(**kwargs).decode(kwargs['encoding']) body = document.toprettyxml(**kwargs).decode(kwargs['encoding'])
# Remove blank lines automatically added by `toprettyxml()`. # Remove blank lines automatically added by `toprettyxml()`.
return '\n'.join(line for line in body.splitlines() if line.strip()) lines = [line for line in body.splitlines() if line.strip()]
# xml.dom automatically adds the declaration, even if
# it is not present in the actual body. Remove it.
if len(lines) >= 1 and parse_declaration(lines[0]):
lines.pop(0)
if declaration:
lines.insert(0, declaration)
return '\n'.join(lines)
class XMLFormatter(FormatterPlugin): class XMLFormatter(FormatterPlugin):
@ -44,6 +63,7 @@ class XMLFormatter(FormatterPlugin):
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
from defusedxml.common import DefusedXmlException from defusedxml.common import DefusedXmlException
declaration = parse_declaration(body)
try: try:
parsed_body = parse_xml(body) parsed_body = parse_xml(body)
except ExpatError: except ExpatError:
@ -54,6 +74,6 @@ class XMLFormatter(FormatterPlugin):
body = pretty_xml(parsed_body, body = pretty_xml(parsed_body,
encoding=parsed_body.encoding, encoding=parsed_body.encoding,
indent=self.format_options['xml']['indent'], indent=self.format_options['xml']['indent'],
standalone=parsed_body.standalone) declaration=declaration)
return body return body

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?><!-- comment -->
<root><element key="value">text</element><element>text</element>tail<empty-element/></root>
<!-- comment -->

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- comment -->
<root>
<element key="value">text</element>
<element>text</element>
tail
<empty-element/>
</root>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<?pi data?> <?pi data?>
<!-- comment --> <!-- comment -->
<root xmlns="namespace"> <root xmlns="namespace">

View File

@ -0,0 +1 @@
<a/>

View File

@ -0,0 +1 @@
<a></a>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- comment --> <!-- comment -->
<root> <root>
<element key="value">text</element> <element key="value">text</element>