mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Refactor XML parsing in rest (#94268)
* Refactor XML parsing in rest * Adjust caplog check * Adjust * Rename * Simplify
This commit is contained in:
parent
61d260e5fe
commit
580b09d0f2
@ -26,3 +26,10 @@ REST = "rest"
|
||||
REST_DATA = "rest_data"
|
||||
|
||||
METHODS = ["POST", "GET"]
|
||||
|
||||
XML_MIME_TYPES = (
|
||||
"application/rss+xml",
|
||||
"application/xhtml+xml",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
)
|
||||
|
@ -3,14 +3,19 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import ssl
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
import httpx
|
||||
import xmltodict
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import template
|
||||
from homeassistant.helpers.httpx_client import create_async_httpx_client
|
||||
from homeassistant.helpers.json import json_dumps
|
||||
from homeassistant.util.ssl import SSLCipherList
|
||||
|
||||
from .const import XML_MIME_TYPES
|
||||
|
||||
DEFAULT_TIMEOUT = 10
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -59,6 +64,26 @@ class RestData:
|
||||
"""Set url."""
|
||||
self._resource = url
|
||||
|
||||
def data_without_xml(self) -> str | None:
|
||||
"""If the data is an XML string, convert it to a JSON string."""
|
||||
_LOGGER.debug("Data fetched from resource: %s", self.data)
|
||||
if (
|
||||
(value := self.data) is not None
|
||||
# If the http request failed, headers will be None
|
||||
and (headers := self.headers) is not None
|
||||
and (content_type := headers.get("content-type"))
|
||||
and content_type.startswith(XML_MIME_TYPES)
|
||||
):
|
||||
try:
|
||||
value = json_dumps(xmltodict.parse(value))
|
||||
except ExpatError:
|
||||
_LOGGER.warning(
|
||||
"REST xml result could not be parsed and converted to JSON"
|
||||
)
|
||||
else:
|
||||
_LOGGER.debug("JSON converted from XML: %s", self.data)
|
||||
return value
|
||||
|
||||
async def async_update(self, log_errors: bool = True) -> None:
|
||||
"""Get the latest data from REST service with provided method."""
|
||||
if not self._async_client:
|
||||
|
@ -3,11 +3,9 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import ssl
|
||||
from xml.parsers.expat import ExpatError
|
||||
|
||||
from jsonpath import jsonpath
|
||||
import voluptuous as vol
|
||||
import xmltodict
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
DOMAIN as SENSOR_DOMAIN,
|
||||
@ -26,7 +24,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.json import json_dumps
|
||||
from homeassistant.helpers.template_entity import TemplateSensor
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
@ -127,26 +124,7 @@ class RestSensor(RestEntity, TemplateSensor):
|
||||
|
||||
def _update_from_rest_data(self) -> None:
|
||||
"""Update state from the rest data."""
|
||||
value = self.rest.data
|
||||
_LOGGER.debug("Data fetched from resource: %s", value)
|
||||
if self.rest.headers is not None:
|
||||
# If the http request failed, headers will be None
|
||||
content_type = self.rest.headers.get("content-type")
|
||||
|
||||
if content_type and (
|
||||
content_type.startswith("text/xml")
|
||||
or content_type.startswith("application/xml")
|
||||
or content_type.startswith("application/xhtml+xml")
|
||||
or content_type.startswith("application/rss+xml")
|
||||
):
|
||||
try:
|
||||
value = json_dumps(xmltodict.parse(value))
|
||||
_LOGGER.debug("JSON converted from XML: %s", value)
|
||||
except ExpatError:
|
||||
_LOGGER.warning(
|
||||
"REST xml result could not be parsed and converted to JSON"
|
||||
)
|
||||
_LOGGER.debug("Erroneous XML: %s", value)
|
||||
value = self.rest.data_without_xml()
|
||||
|
||||
if self._json_attrs:
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
@ -899,7 +899,7 @@ async def test_update_with_xml_convert_bad_xml(
|
||||
state = hass.states.get("sensor.foo")
|
||||
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert "Erroneous XML" in caplog.text
|
||||
assert "REST xml result could not be parsed" in caplog.text
|
||||
assert "Empty reply" in caplog.text
|
||||
|
||||
|
||||
@ -936,7 +936,7 @@ async def test_update_with_failed_get(
|
||||
state = hass.states.get("sensor.foo")
|
||||
|
||||
assert state.state == STATE_UNKNOWN
|
||||
assert "Erroneous XML" in caplog.text
|
||||
assert "REST xml result could not be parsed" in caplog.text
|
||||
assert "Empty reply" in caplog.text
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user